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.