Troubleshooting
This page collects the recurring "user reports X" cases and the runbook
queries that diagnose them. Every query runs on the contributor portal
Supabase project (xlsjwlmsqonllvtyplml) unless otherwise stated.
Tip: in the Supabase MCP
playroll_supa_portal, paste the queries directly. They're written so the only thing that changes per case is the email at the top.
"Non mi è arrivata la mail di conferma IBAN"
The single most common report. Symptoms: user completed the IBAN form but hasn't received the magic link to confirm; or received it but it now says "link scaduto".
Step 1 — does the user exist in auth?
select id, email, created_at, last_sign_in_at,
email_confirmed_at, confirmation_sent_at, recovery_sent_at
from auth.users
where email = 'user@example.com';
If empty, the user never reached signInWithOtp. Tell them to try the
flow from scratch and to look in their browser console / network tab for
errors. Likely an ad-blocker or a bad network.
Step 2 — what's the state of their payout method?
select id, method_type, status, email_confirmation_status,
email_confirmation_sent_at, email_confirmed_at,
iban_last4, created_at, updated_at
from public.payout_receiving_methods
where lower(verified_email) = 'user@example.com'
order by created_at desc;
Possible states:
status | email_confirmation_status | What it means |
|---|---|---|
pending_email_confirmation | pending | Mail was sent. The link they clicked was probably expired. Tell them to request a new confirmation link via the portal (they'll need to log back in and re-submit). |
confirmed | confirmed | All good. They're confused — re-direct them to the portal to see the green badge. |
manual_review | n/a | Manual review path, not an email-confirmation case. |
| (no row) | They never submitted the IBAN. |
Step 3 — what does telemetry say?
with hash as (
select public.telemetry_email_hash('user@example.com') as eh
)
select occurred_at, event_name, severity, error_code, error_message, attrs
from public.telemetry_events, hash
where telemetry_events.email_hash = hash.eh
or telemetry_events.auth_user_id = (
select id from auth.users where email = 'user@example.com'
)
order by occurred_at desc
limit 50;
Look for the sequence:
payout.receiving_method.submitted— they clicked "Save IBAN"auth.otp.requested(intent: payout) — portal asked Supabase Auth to send the magic linkauth.otp.sent— Supabase Auth confirmed it sent itpayout.receiving_method.confirmed— they clicked the link
If 1+2 are present but 3 isn't, Supabase Auth refused (rate-limit, SMTP
error). Check auth.audit_log_entries (next case).
Real case (Philip, 2026-05-03): he submitted the IBAN, the mail was sent successfully, but the link sat in his Gmail Promotions tab unread for 11 days. When asked to check spam he found it. No code change needed.
"L'app PlayRoll dice ancora 'Not verified' anche se ho finito sul portale"
The portal completes the bridge by writing into contributor_status_projection
on the app Supabase project (vtyolotvuvlbvqbgbzde). The two flows
(app-first / portal-first) fail in different
ways.
Mode A — portal-first activation code never redeemed. If the user signed up on the portal without going through the app's "Collega account" button, they need to generate an activation code on the portal (Rewards section → "Genera codice") and paste it in the app (Settings → Account contributor → Riscatta). Until they do, no Steam ID is bound and the badge stays "Not verified".
-- portal: did they ever generate a code?
select id, status, issued_at, expires_at, redeemed_at, redeemed_app_user_id
from public.recorder_activation_codes
where portal_auth_user_id = (
select id from auth.users where email = 'user@example.com'
)
order by issued_at desc;
If status = 'issued' and expires_at > now() they have a valid code
but never pasted it in the app. If status = 'expired' or all rows are
revoked, walk them through generating a fresh one. If status = 'redeemed'
the bridge already ran — jump to Mode B below.
Mode B — bridge fired but didn't activate. Check both projects:
-- portal (xlsjwlmsqonllvtyplml)
select id, status, app_user_id, intent_nonce, linked_at
from public.contributor_app_links
where portal_auth_user_id = (
select id from auth.users where email = 'user@example.com'
);
-- app (vtyolotvuvlbvqbgbzde)
select * from public.contributor_status_projection
where app_user_id = '<the app_user_id from above>';
If the portal row is pending_activation, the gate (onboarding submitted
- payout confirmed) wasn't complete when the activation fired. Tell the user to complete the missing step and reload the portal — the dedup hook will retry within ~30s of the gate being satisfied.
If the portal row is active but the app row is missing, the
cross-project write failed. This is a real bug and needs an engineer:
check the activate-contributor-app-link edge function logs around the
activation timestamp.
"Vedo errori a caso nella console del portal"
The portal emits ui.unhandled_error, ui.unhandled_rejection, and
ui.error_boundary events to the same telemetry_events table. Recent
crashes:
select occurred_at, event_name, attrs->>'scope' as scope,
error_message, attrs->>'component_stack' as component_stack
from public.telemetry_events
where event_name like 'ui.%'
and severity in ('error', 'fatal')
and occurred_at > now() - interval '1 hour'
order by occurred_at desc;
Group by error_message to spot recurring bugs:
select error_message, count(*) as occurrences,
count(distinct session_id) as affected_sessions,
max(occurred_at) as last_seen
from public.telemetry_events
where event_name = 'ui.error_boundary'
and occurred_at > now() - interval '7 days'
group by error_message
order by occurrences desc;
"Una mia chiamata Supabase è in errore ma non vedo niente in UI"
Should not happen anymore after EC-189: the four read-side helpers
(loadLatestApplication, loadLatestOnboardingSubmission,
loadLatestPayoutReceivingMethod, loadContributorDashboard) now show
a toast via showSupabaseError() and emit ui.toast.shown telemetry.
If a write call (insert/update/RPC) returns an error and the user sees
nothing, that's a bug — check the form's submit handler in
src/features/portal/usePortalFlow.ts, the error is probably swallowed.
"Voglio vedere il funnel onboarding negli ultimi giorni"
select date_trunc('day', occurred_at) as day,
event_name,
count(distinct auth_user_id) as users
from public.telemetry_events
where event_name in (
'auth.otp.requested',
'auth.otp.sent',
'payout.receiving_method.submitted',
'payout.receiving_method.confirmed',
'app_link.activate.verified'
)
and occurred_at > now() - interval '7 days'
group by day, event_name
order by day desc, event_name;
Looking for big gaps between one step and the next — that's where users are dropping off.