Campanhas, Premium e indicação¶
Campanhas¶
Campanhas são administradas pelo Super Admin. O backend aceita a matriz:
stateDiagram-v2
[*] --> draft
draft --> scheduled
draft --> open_for_partners
draft --> cancelled
scheduled --> open_for_partners
scheduled --> active
scheduled --> cancelled
open_for_partners --> active
open_for_partners --> cancelled
active --> ended
active --> cancelled
ended --> archived
createCampaign sempre cria em draft. updateCampaign só altera campanhas draft|scheduled. changeCampaignStatus valida a matriz em transação; ao encerrar, expira ofertas de campanha active|approved em lotes de até 400.
Dois schedulers completam o ciclo temporal:
autoTransitionCampaigns:scheduled → open_for_partnersquando começa a submissão escheduled|open_for_partners → activeno início da campanha;closeExpiredCampaigns:active → endedao atingircampaignEndAt, seguido da expiração das ofertas relacionadas.
Ambos são acionados a cada minuto, mas respeitam os intervalos configurados em settings/schedulers.
Participação do parceiro¶
joinCampaign deriva o partner pelo owner_uid, exige campanha aberta e grava o ID determinístico {campaignId}_{partnerId} como interested. withdrawCampaignParticipation impede desistência de participação approved.
submitCampaignOffer exige janela de submissão aberta, participação existente, ownership de todas as unidades e payload coerente com discount ou buyMore. Cria uma oferta por unidade com:
source: campaign;status: pending_review;visibilityTier: free;campaignId,partnerIderestaurantIdderivados/validados;- participação atualizada para
submittedno mesmo batch.
Premium com Stripe¶
O acesso pago segue o webhook como fonte de verdade:
sequenceDiagram
participant App
participant CF as Cloud Functions
participant Stripe
participant DB as Firestore
App->>CF: createStripeCheckoutSession(plan)
CF->>Stripe: cria/recupera customer e Checkout Session
CF-->>App: URL da sessão
Stripe->>CF: stripeWebhook assinado
CF->>DB: reserva stripeEvents/{eventId}
CF->>DB: sincroniza subscriptions/{uid} e users/{uid}
Planos aceitos: premium_monthly e premium_launch. Os estados active|trialing concedem premiumAccessSource: subscription; estados não ativos removem essa origem se ela ainda for subscription.
Eventos processados:
checkout.session.completed;invoice.paid;invoice.payment_failed;customer.subscription.created|updated|deleted.
stripeEvents reserva o ID em transação e impede processamento concorrente/duplicado. Checkout, Portal e webhook exigem os segredos descritos em Configuração.
Indicação¶
submitReferralCode normaliza o código, proíbe autoindicação e troca de código. Se phone_verified já for verdadeiro, aplica a recompensa imediatamente; caso contrário, aguarda o trigger de criação/atualização do usuário.
referralEngine executa transação, procura o indicador, impede duplicidade pelo par indicador/convidado, cria uma recompensa disponível e marca referralRewardClaimed. O fluxo também grava audit_referrals, inacessível diretamente pelos clientes.
Recompensas compatíveis podem autorizar um único cupom Premium quando o usuário não possui assinatura/admin grant. A geração do cupom reserva e consome a recompensa na mesma transação.
Exclusão de conta¶
deleteUserAccount exige autenticação e pode cancelar assinatura Stripe ativa. Dados pessoais são excluídos ou redigidos em lotes/transações; histórico financeiro e operacional é preservado de forma redigida quando necessário. Para conta de parceiro, integrações, garçons, sessões, unidades e documento do partner são removidos, enquanto cupons/ofertas são redigidos.
Storage
O código remove referências de imagem de documentos durante a exclusão, mas a remoção física segura dos objetos no Storage permanece pendente na implementação. Não trate a exclusão do documento como prova de remoção do arquivo.