Persistência e segurança¶
Coleções Firestore¶
| Coleção | Escrita principal | Leitura cliente |
|---|---|---|
users |
próprio usuário em campos permitidos; backend para Premium/referral | próprio usuário ou Super Admin |
partners |
owner cria/atualiza; Super Admin administra | autenticados |
stores |
owner do partner em campos permitidos; Super Admin | autenticados |
offers |
partner em oferta regular segura; Functions para ações críticas | autenticados |
coupon_redemptions |
somente Admin SDK/Functions | dono, Super Admin, owner do partner ou sessão de garçom da unidade |
waiters |
owner da unidade/Super Admin | owner da unidade/Super Admin |
waiter_sessions |
somente Functions | negada diretamente |
campaigns |
somente Functions | não-draft para autenticados; todas para Super Admin |
campaign_participations |
somente Functions | partner proprietário ou Super Admin |
referral_rewards |
somente Functions | usuário beneficiário ou Super Admin |
subscriptions |
webhook/backend | próprio usuário ou Super Admin |
stripeEvents |
webhook/backend | Super Admin |
settings |
Super Admin | Super Admin |
partner_integrations |
owner do partner | autenticados |
audit_referrals |
backend | negada diretamente |
Ofertas possuem subcoleções privadas:
offers/{offerId}/admin_notes— somente Super Admin lê;deletion_context— contexto usado antes do delete, somente Super Admin lê;audit_logs— Super Admin e owner atual do partner leem; backend escreve.
products permanece legível por autenticados, mas write é negado. O catálogo atual usa offers como fonte principal.
Firestore Rules¶
firestore.rules aplica deny-by-default. Os helpers resolvem ownership por documentos partners e stores, protegem campos curatoriais/Stripe, validam categorias/badges e impedem que clientes modifiquem contadores de cupons.
Regras importantes:
- clientes nunca escrevem
coupon_redemptions, campanhas, participações, rewards ou subscriptions diretamente; - parceiros não mudam autoria, tier de visibilidade, campos curatoriais, origem/campanha nem contadores de limite;
- Super Admin também não altera diretamente os contadores operacionais de limite;
- ofertas não podem ser deletadas diretamente;
- fallback global nega toda rota não declarada.
O Admin SDK usado pelas Functions não é limitado por Rules. Cada Function precisa repetir autenticação, role, ownership e validação de estado.
Índices¶
firestore.indexes.json versiona índices compostos para:
- cupons por usuário/status, unidade/status/data, partner/status/data, cooldown e expiração;
- ofertas por status/data, partner/status e combinações de campanha;
- campanhas por status e datas/prioridade;
- rewards por usuário/data.
Ao alterar uma query com múltiplos filtros/ordenação, reproduza-a no emulador e mantenha o índice no mesmo commit.
Storage¶
storage.rules permite leitura pública de imagens e limita escrita a arquivos image/* menores que 8 MiB:
| Prefixo | Quem escreve |
|---|---|
offers/{partnerId}/... |
owner do partner |
stores/{partnerId}/... |
owner do partner |
campaigns/{campaignSlug}/... |
Super Admin |
public/... |
Super Admin |
Qualquer outro caminho é negado. O content type vem do request; consumidores ainda devem tratar arquivos como conteúdo não confiável.
Segredos e identidade¶
- Firebase client options em
firebase_options.dartidentificam o projeto, mas não são credenciais administrativas. - Service accounts,
.env*, keystores efunctions/.secret.localdevem permanecer fora do Git. - Stripe usa
defineSecret; não há fallback seguro para produção sem Secret Manager. super_adminé custom claim, não um campo de tela.- O monitor do garçom usa Auth anônimo apenas como identidade de sessão; autorização operacional vem de
waiter_sessionscriado após e-mail/PIN válidos.
Auditoria¶
O trigger onOfferWritten usa auth context quando disponível para produzir trilha de criação/alteração/deleção. A deleção callable grava contexto no mesmo batch em que remove a oferta, permitindo ao trigger recuperar metadados.
Logs de aplicação não substituem audit logs persistidos. Evite registrar PIN, tokens, payload completo Stripe ou PII desnecessária em console.*.