Passa al contenuto principale

Release e Notifiche

Riepilogo in linguaggio semplice. Due sistemi di consegna condividono questa pagina perché svolgono lo stesso tipo di compito: decidere chi riceve cosa, e quando. Il sistema di release decide a quale build dell'app un dato install deve aggiornarsi (per track, per percentuale, per bucket A/B, con override d'emergenza). Il sistema di notifiche decide quali messaggi in-app/email un dato giocatore vede, e ricorda se li ha letti.

Parte 1 — Release e rollout dell'app

Mappa

Come viene risolto un aggiornamento

Quando un client chiede "c'è un aggiornamento per me?", la edge function resolve-update percorre queste tabelle e scrive una riga di audit. I pezzi:

  • app_releases_v2 — una build pubblicata. Raggruppa le tre versioni che vengono distribuite insieme (installer_version, core_version, ui_version) sotto una release_key, su un release_track — un insieme chiuso di tre valori: stable | dev | test (non esiste beta; dev/test sono privati, gestiti tramite allowlist). Più un download_url, l'integrità installer_sha256, e le note di rilascio sia rivolte all'utente sia tecniche.
  • app_rollouts_v2 — una regola che espone una release a una fetta della flotta: un track (default stable), una percentage (0–100, default 100), experiment_key / ab_bucket opzionali (A/B/null) per i test A/B, array espliciti include_user_ids / exclude_user_ids / include_install_ids, una priority (default 100; valore più basso = precedenza più alta), un flag force_update (default false), un gate enabled (default true — i rollout disabilitati vengono saltati), e una finestra temporale (starts_at / ends_at).
  • app_rollout_overrides_v2 — una via di fuga per singolo target: fissa uno specifico target_type (user | install) + target_id a una release_id, con un flag enabled, force_update (qui default true — nota la differenza rispetto ai rollout), un reason, e expires_at. Univoco su (target_type, target_id). È così che si esegue un hotfix per un singolo utente o si forza un aggiornamento critico al di fuori della rampa normale.
  • app_update_resolve_audit_v1una riga per ogni esito di risoluzione significativo (25 colonne), deduplicata da should_write_resolve_audit così che risoluzioni identiche/no-op non riempiano la tabella di righe. Registra lo stato attuale dell'install (installed_*_version, installed_track), cosa è stato deciso (assignment_sourcerollout / override / noneassignment_track, rollout_id, override_id, bucket), e l'esito (target_release_id, le versioni di destinazione, update_available, update_required, force_update, reason). È questa la tabella da interrogare per rispondere a "perché questa macchina ha ricevuto / non ha ricevuto l'aggiornamento?"

Ordine di risoluzione: gli override vincono per primi (un override user prima di un override install); altrimenti il resolver prova i rollout abilitati in ordine (priority ASC, created_at ASC) e vince il primo che qualifica (la priority è la chiave di selezione primaria, non solo un tie-break). Quando non viene selezionato nulla, assignment_source = 'none'.

  • app_update_resolve_rate_limit — contatori a finestra fissa chiavati su (ip_sha256, finestra 60s) così che l'endpoint pubblico di risoluzione non possa essere martellato. Le righe vecchie vengono potate a ogni controllo.

La view user_current_track deriva il release track corrente di ciascun utente dall'ultimo installed_track nella tabella di audit; resolve_audience() la usa per il filtro di notifica app_track. Vedi Fasi e Policy del Programma e il runbook Workflow di Release e CI.

Parte 2 — Notifiche

Mappa

Le FK degli utenti puntano a auth.users, non a playroll_users

Le colonne user_id / added_by / created_by sulle tabelle di notifica fanno tutte FK a auth.users(id) (stesso UUID di playroll_users, tabella fisica diversa), ON DELETE CASCADE (eccetto created_by/added_by, che fanno SET NULL). Il diagramma le disegna verso PLAYROLL_USERS per leggibilità. Chiavi di idempotenza: notification_deliveries è UNIQUE su (event_id, user_id, channel), la PK di notification_state è (event_id, user_id).

La forma di una notifica

  • notification_event — il messaggio redatto. Una riga per notifica. Il suo urgency_tier è un enum stretto T0 | T1 | T2 | T3 che porta con sé un comportamento: T0 richiede una CTA, forza in_app + email, e non può essere disattivato; i tier inferiori vengono instradati per tier + category. source ∈ (backend, portal, release, ops_admin, discord_bridge); locale ∈ (it, en) (default it). category è testo libero — nessun CHECK (es. payment_readiness, app_update); non è un enum chiuso. Porta anche type, payload / cta (jsonb), allowed_channels (default {in_app}), il jsonb audience_filter (risolto da resolve_audience()), un recipient_count denormalizzato, e un expires_at opzionale.
  • notification_deliveries — il fan-out solo per i canali esterni: una riga per ogni tentativo (event, user, channel) dove channel ∈ (email, push, discord). in_app non è qui di proposito — viene servito da notification_state. status ∈ (queued [default], sent, failed, skipped), con error_code, queued_at, sent_at. UNIQUE su (event_id, user_id, channel) per idempotenza.
  • notification_state — il record di engagement per singolo utente (e la superficie di consegna in_app): quando un utente ha eseguito read_at / dismissed_at / acted_at su un dato evento. PK (event_id, user_id). Alimenta il badge dei non letti e le metriche di azione-su-CTA.
  • notification_groups + notification_group_members — coorti nominate (founders, ops, beta…) che puoi usare come target, invece di elencare gli user id ogni volta. Un gruppo ha uno slug/name; l'appartenenza è (group_id, user_id).
  • notification_user_prefs — gli interruttori di ciascun utente (enable_payment_and_validation, enable_app_update_and_terms, enable_catalog_and_announcements, enable_sound, enable_email; categorie + email default true, suono default false). Importante: la riga viene creata in modo lazy — l'assenza significa "opt-in (default)". E la consegna lato server (emit_notification) attualmente consulta solo enable_email (per gli invii email non-T0); i tre toggle di categoria e enable_sound sono memorizzati ma consumati lato client / non ancora applicati alla consegna. Il mapping category→toggle stesso vive nel codice applicativo (le stringhe category non corrispondono letteralmente ai nomi delle colonne), non nel DB.

Vedi Flusso di Consegna delle Notifiche e il runbook Ops del Composer delle Notifiche per il ciclo di vita redazione → consegna → stato.


Vedi anche: riferimento completo delle colonne per release e notifiche.