Pular para conteúdo

Arquitetura

Separação principal

O AiValeu combina Clean Architecture nos packages compartilhados com organização feature-first nas aplicações.

flowchart LR
  UI[Presentation\nWidgets + Cubits/Blocs] --> UC[Use cases]
  UC --> CONTRACTS[Repository contracts]
  CONTRACTS --> IMPL[Repository implementations]
  IMPL --> FIRESTORE[(Firestore)]
  IMPL --> FUNCTIONS[Cloud Functions]
  FUNCTIONS --> FIRESTORE
  FUNCTIONS --> EXTERNAL[Stripe / serviços externos]

Domain

packages/aivaleu_domain contém entidades, value objects, contratos e use cases. Seu pubspec.yaml depende apenas de equatable, além das dependências de teste. Essa camada é o melhor lugar para regras que devem ser testadas sem Flutter ou Firebase.

Data

packages/aivaleu_data implementa os contratos do domínio. Ele conhece Firestore, Firebase Auth e Cloud Functions. Exemplos centrais:

  • OfferRepositoryImpl: leitura de ofertas, feed, curadoria e criação administrativa;
  • CouponRepositoryImpl: ciclo de cupom;
  • CampaignRepositoryImpl: leitura e mutação de campanhas;
  • WaiterRepositoryImpl: garçons, fila de check-in e confirmação;
  • PremiumRepositoryImpl: entitlement e entrada para Stripe.

Presentation

Cada app compõe repositórios/use cases via GetIt e expõe estado com Cubit/Bloc. A UI não é barreira de segurança: operações críticas são novamente verificadas no backend.

Limites de confiança

Camada Pode decidir
Widget/Cubit Estado de interface, navegação, validações de UX.
Use case Regra de aplicação que não exige segredo/autoridade externa.
Repository Tradução entre domínio e fonte de dados.
Cloud Function Mutações privilegiadas, transações, integrações secretas e decisões server-side.
Firestore/Storage Rules Última barreira para acesso direto de clientes Firebase.
Remote Config Flags e apresentação; nunca autorização, pagamento ou quota.

Padrões de consistência

Transações

Capacidade de cupons é protegida por Firestore Transaction. Reservar, consumir e liberar vaga atualiza cupom e oferta de forma atômica.

Backend-first para ranking

O app solicita ao getOfferFeed somente a ordem/metadata de ranking e depois busca os documentos de oferta. A lista é reconstruída na ordem retornada pela Function.

Fallbacks

OfferRepositoryImpl.getFeedOffers possui fallback Firestore caso o backend de ranking falhe ou a localização não esteja disponível. O fallback mantém o feed operável, mas não reproduz geofiltro nem embaralhamento ponderado.

Auditoria por trigger

Escritas em offers/{offerId} disparam onOfferWritten com contexto de autenticação. O log é derivado da mudança real e gravado em subcoleção protegida.