Passa al contenuto principale

Modello Dati

Lo schema del portale è definito in supabase/migrations/. RLS è abilitata su tutte le tabelle relative a contributor, documenti, sessioni, compensation, payout, ricevute, cap, eccezioni e audit.

Ordine delle Migrazioni

20260430233000_initial_portal_schema.sql
20260501133000_add_onboarding_document_acceptance_evidence.sql
20260501193000_add_validation_rewards_payout_flow.sql
20260501194500_add_playroll_time_milestones.sql
20260501200000_add_payout_receiving_methods.sql
20260501201000_lock_payout_receiving_method_confirmation.sql
20260501204000_validate_payout_receiving_iban.sql
20260511161000_add_contributor_app_links.sql

Shortcut in package.json:

npm run deploy:schema
npm run deploy:schema:validation-payout
npm run deploy:schema:time-milestones
npm run deploy:schema:payout-receiving
npm run deploy:schema:payout-iban-validation

Tabelle Scritte dal Browser

public.applications

Scritta da insertVerifiedApplication.

Campi principali:

auth_user_id
legal_name
email
email_verified_at
city
university
discord_handle
weekly_availability
notes
privacy_notice_version
referral_code
source
status
metadata.city
metadata.university

Confine di sicurezza:

  • solo insert autenticate
  • auth_user_id = auth.uid()
  • l'email inviata deve coincidere con l'email verificata su Supabase
  • email_verified_at deve essere presente
  • il contributor può leggere solo le proprie righe

public.onboarding_submissions

Scritta da insertOnboardingSubmission.

Campi principali:

auth_user_id
application_id
invite_code
legal_name
email
city
contact_handle
tax_status
accepted_documents
document_acceptance_evidence
metadata.city
metadata.sensitive_data_collection
metadata.payout
metadata.recorder_access

La tabella ha ancora colonne di compatibilità per date_of_birth, residential_address, codice_fiscale, account_holder_name e iban. Il portale attualmente visibile non raccoglie questi valori prima dell'accesso al recorder.

public.payout_receiving_methods

Scritta da savePayoutReceivingMethod (INSERT, più UPDATE a livello di colonna su account_holder_name/manual_review_note/metadata). Le colonne status, email_confirmation_status, email_confirmed_at e confirmation_token sono scrivibili soltanto attraverso le RPC SECURITY DEFINER mint_payout_confirmation_token(p_method_id) e confirm_payout_receiving_method_with_token(p_token) (audit 2026-05-16, EC-231 M1+M2).

Campi principali:

auth_user_id
verified_email
method_type
account_holder_name
iban
iban_last4
manual_review_note
email_confirmation_status
email_confirmation_sent_at
email_confirmed_at
status
confirmation_token
confirmation_token_expires_at
metadata

Metodi consentiti:

sepa_iban
manual_review

Stati operativi:

pending_email_confirmation
confirmed
manual_review
disabled

Le funzioni di database normalizzano e validano gli IBAN SEPA supportati:

public.normalize_iban(value text)
public.is_supported_sepa_iban(value text)
public.normalize_payout_receiving_method_iban()

La policy di insert richiede email_confirmation_status = pending e limita gli stati inseribili:

method_type = sepa_iban -> status = pending_email_confirmation
method_type = manual_review -> status = manual_review

Gli update sono consentiti soltanto finché la riga attiva dell'utente è ancora pending_email_confirmation o manual_review.

Tabelle di Reward e Payout

Lo schema include il modello di reward e di pagamento a valle, ma il portale attuale non lo gestisce interamente dal browser.

Source of truth della validazione:

public.session_validation_results

Regola importante:

public.session_validation_results.status = validated

La validazione non deve calcolare direttamente gli EUR pagabili. payable_eur è deprecato e deve rimanere a 0.

Source of truth del time-credit:

public.playroll_time_ledger

Source of truth dei milestone:

public.reward_milestones
public.contributor_milestone_unlocks

Source of truth dei valori:

public.compensation_items

Vista del saldo denaro/reward:

public.contributor_reward_balances

Vista di esportazione del receiving-method:

public.confirmed_payout_receiving_methods

Viste Principali

Viste di saldo visibili al contributor:

public.contributor_playroll_time_balances
public.contributor_milestone_progress
public.contributor_reward_balances

Queste viste sono create con security_invoker = true e concesse agli utenti authenticated. La RLS continua a controllare la visibilità delle righe attraverso la relazione contributor/user sottostante.

La tabella del portale che funge da source per il ponte app Playroll/contributor è:

public.contributor_app_links

Campi importanti:

id
contributor_id
portal_auth_user_id
app_project
app_user_id
steam_id
steam_username
status
intent_issued_at
intent_expires_at
intent_nonce
pending_expires_at
linked_at
revoked_at

Stati:

pending_activation
active
revoked

Vincoli e indici garantiscono:

one active link per app_project + app_user_id
one active link per app_project + contributor_id
one pending link per app_project + app_user_id + portal_auth_user_id
one recorded intent_nonce per app_project

Helper di attivazione:

public.has_completed_contributor_activation_gate()
public.ensure_current_contributor()

Il gate di attivazione richiede tutte le accettazioni dei documenti necessarie e un receiving-method SEPA IBAN confermato. manual_review non è sufficiente per l'attivazione automatica.

Il progetto dell'app Playroll possiede la proiezione di lettura:

playroll_supa_new.public.contributor_status_projection

Campi importanti:

app_user_id
contributor_id
link_status
source_link_id
steam_id
linked_at
source_updated_at
last_synced_at

La RLS consente agli utenti authenticated dell'app di leggere solo la propria riga di proiezione. La proiezione è volutamente minimale e non deve contenere evidenze di documenti legali, dati IBAN, dettagli del metodo di payout o altre PII del portale.

Helper RLS

La migrazione iniziale definisce:

public.current_contributor_id()
public.is_ec_domain_user()

public.current_contributor_id() supporta l'accesso own-row del contributor. public.is_ec_domain_user() è riservato per una futura admin surface e non deve essere usato per limitare l'accesso alla pagina pubblica di candidatura.

Confine Admin/Service-Role

Le seguenti operazioni non devono essere di proprietà del browser:

  • creazione di record canonici di contributor al di fuori di ensure_current_contributor() dopo il gate di attivazione
  • assegnazione di sessioni del recorder
  • scrittura dei risultati di validazione
  • creazione di voci nel PlayRoll time ledger
  • sblocco di milestone
  • creazione di compensation item a partire dai milestone
  • creazione di richieste di payout
  • approvazione e invio dei pagamenti
  • generazione di ricevute o value sheet
  • calcolo degli snapshot di cap
  • risoluzione delle eccezioni