# Modelo de dados Source: https://developers.googa.com.br/architecture/data-model O vocabulário de entidades por trás da API — Subscriber, User, Reader/Listener, o grafo de conteúdo, Entitlement e Event — sem expor o schema SQL completo. Esta página descreve **conceitos**, não o schema físico. Os nomes de tabela citados (`profiles`, `novels`, `subscriptions`...) existem dentro de cada projeto Supabase de produto — o vocabulário de API (`Subscriber`, `Entitlement`, `Event`) é a camada de parceiro que se apoia neles. Onde os dois convergem, dizemos explicitamente. ## Três identidades que parecem uma O erro mais comum ao integrar é tratar "o assinante" como uma linha única. São três conceitos diferentes, em três lugares diferentes, e a API de parceiro existe justamente para costurá-los sem que quem integra precise saber onde cada um mora: | Conceito | O que é | Onde vive | Quem o possui | | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------- | | **Subscriber** | A identidade do lado do parceiro — o assinante do plano Algar que inclui o benefício Googa | `partner_subscribers` (com `partner_id`), dentro do projeto Supabase de cada produto | O parceiro (Algar conhece esse ID antes de qualquer chamada à Googa) | | **User** | A identidade Supabase — quem efetivamente autenticou (e-mail/senha, ou SSO via Minha Algar) | `auth.users`, dentro do projeto do produto (Novel ou HistorinhAI) | O produto | | **Reader / Listener / perfil de criança** | O perfil de consumo dentro de um produto — preferências, progresso, o que aquela pessoa (ou aquela criança) já leu/ouviu | `profiles` (NovelAI/NovelÁudio) ou `profiles` + `children` (HistorinhAI) | O produto | A relação entre os três é 1:N descendo: um `Subscriber` pode, via SSO, corresponder a um `User` em cada produto que ele ativa (o `sub` do token da Algar fica gravado em `auth.identities`, o `subscriber_id` em `app_metadata` — ver [Modelo de autenticação](/architecture/supabase-auth-model)); e um `User` tem exatamente um perfil por produto — exceto no HistorinhAI, onde o `User` é o responsável (pai/mãe) e não quem consome o conteúdo. Aqui `User` e "Reader/Listener" colapsam na prática: a tabela `profiles` é 1:1 com `auth.users`, e a única diferença entre um "Reader" e um "Listener" é a coluna `app_source` (`novelai` ou `novelaudio`) — porque os dois produtos compartilham o mesmo projeto Supabase (ver [Modelo multi-tenant](/architecture/multi-tenant-model)). "Reader" e "Listener" são vocabulário de API para diferenciar a intenção do produto, não duas tabelas diferentes. Aqui a distinção é real, não só semântica: `profiles` é o responsável — a pessoa que autentica, paga, e gerencia a conta (limite de 6 perfis por conta). A criança nunca autentica: ela existe como uma linha em `children` (nome, data de nascimento, preferências), sem identidade Supabase própria. O equivalente a "Reader" no vocabulário do HistorinhAI é o perfil de criança — e é por isso que o relatório mensal (RFP, página 17-19) é agregado por criança, não por conta. ## Conteúdo: Novel → Chapter → Page O catálogo tem cinco níveis, com a granularidade pensada para separar o metadado de capítulo (usado pelo player de áudio) do conteúdo de leitura em si: ```mermaid theme={null} erDiagram CATEGORY ||--o{ NOVEL : organiza NOVEL ||--o{ CHAPTER : "tem (drip: 1/dia; final junto com o 7º)" CHAPTER ||--o{ PAGE : "tem (7 por capítulo de conteúdo)" NOVEL ||--o{ CHOICE : "oferece (no capítulo final)" ``` * **Category** — agrupamento editorial do catálogo (ex: "coreana", "fantasia") — leitura pública, sem autenticação. * **Novel** — a obra em si (título, sinopse, tags) — metadado público; conteúdo exige login. * **Chapter** — a unidade do drip diário: um capítulo novo é liberado por dia, por leitor, por obra (`unlocked_chapter_count`). Guarda metadado (título, duração — usado pelo menu do player de NovelÁudio). * **Page** — a unidade de conteúdo dentro do capítulo. **Cada capítulo de conteúdo tem 7 páginas**, liberadas juntas quando o capítulo é desbloqueado — não uma página por dia. Essa granularidade existe para separar "o que o motor de drip libera" (capítulo) de "como o conteúdo é paginado na leitura" (página), sem mudar o ritmo do drip nem o preço. * **Choice** — os finais (tipicamente 4, por obra) vivem em um **capítulo final próprio** (o 8º em `novel_chapters`, só metadado — a tela de escolha, sem páginas de conteúdo), liberado **no mesmo dia** em que o último capítulo de conteúdo (o 7º) libera. Só ficam visíveis quando esse capítulo final libera para aquele leitor. NovelÁudio espelha exatamente esse grafo — mesma obra, mesmos capítulos, mesmos finais — só a unidade de progresso é diferente: `reading_progress` (NovelAI) guarda o **capítulo** alcançado; `listening_progress` (NovelÁudio) guarda **capítulo + posição em segundos** dentro do áudio pré-renderizado daquele capítulo. São conceitos de progresso deliberadamente separados, porque a semântica de "onde você está" é diferente entre ler e ouvir. HistorinhAI não compartilha esse grafo — seu catálogo é `themes` → `stories`, mais simples, porque não há ramificação de narrativa nem drip diário: a seleção da história certa por perfil de criança é decidida pela geração personalizada (RFP, página 17-19), não por um calendário fixo de capítulos. ## Entitlement: a ponte entre Subscriber e Product `Entitlement` é o conceito que a API de parceiro expõe (`POST /entitlements`, `GET /subscriber-status/{id}` — ver [Platform API](/platform/overview)) para responder uma pergunta: **este Subscriber tem acesso a este Product agora?** Internamente, o entitlement de parceiro é gravado em uma tabela **própria**, `partner_subscribers` (chave `(partner_id, subscriber_id, product)`), dentro do projeto Supabase de cada produto: quando o Partner Gateway (projeto Platform) recebe `POST /entitlements`, ele roteia para a Edge Function de domínio do produto correspondente (`entitlements-novelai`, por exemplo), que faz o upsert nessa tabela. Isso é **deliberado**: enquanto o SSO não existe, não há `user_id` real para ligar o `subscriber_id` do parceiro a uma conta do app — então nada toca a tabela `subscriptions` do app oficial (que tem chave `(user_id, app)` e coluna `source` distinguindo `app`, `stripe`, `revenuecat`). Quando o SSO existir, um passo de vínculo preencherá o `user_id` em `partner_subscribers` e/ou provisionará `subscriptions` com `source = 'partner'` — reaproveitando a lógica de gating (drip, TTS, streaming) que já lê `subscriptions` hoje, sem que nenhuma tabela de domínio do leitor precise saber sobre parceiros. Um Subscriber pode ter zero, um, ou até três Entitlements simultâneos (um por produto) — é isso que permite ao parceiro ativar "só NovelAI" ou "os três produtos" para o mesmo assinante sem nenhuma mudança de schema (ver [Modelo multi-tenant](/architecture/multi-tenant-model)). ## Event: a base dos webhooks `Event` é a abstração por trás de `subscriber.updated` e `subscription.canceled` (ver [Platform API — Eventos](/platform/overview#eventos-webhooks-de-saída)). Não existe uma tabela `events` genérica — o mecanismo real é um Database Webhook (trigger Postgres via `pg_net`) disparando na mudança de linha de `partner_subscribers` e invocando a função intermediária `webhook-dispatch` (projeto Platform), que assina o payload com HMAC-SHA256 e o entrega ao `webhook_url` do parceiro em **uma única tentativa** — não há fila própria de reentrega. Do ponto de vista de quem integra, `Event` é o contrato estável (nome do evento + payload); do ponto de vista da implementação, é uma consequência direta de uma escrita que já aconteceria de qualquer forma — não um sistema de mensageria adicional para operar. ## Visão consolidada ```mermaid theme={null} erDiagram PARTNER ||--o{ SUBSCRIBER : possui SUBSCRIBER ||--o{ ENTITLEMENT : tem SUBSCRIBER ||--o| USER : "vincula-se via SSO" USER ||--o| PROFILE : "1:1 (NovelAI/NovelÁudio)" USER ||--o{ CHILD_PROFILE : "1:N, até 6 (HistorinhAI)" ENTITLEMENT ||--o{ EVENT : "gera ao mudar" ENTITLEMENT }o--|| PRODUCT : "concede acesso a (NovelAI/HistorinhAI/NovelÁudio)" PRODUCT ||--o{ NOVEL : "catálogo (NovelAI/NovelÁudio)" NOVEL ||--o{ CHAPTER : "drip diário" CHAPTER ||--o{ PAGE : "7 por capítulo" ``` `PARTNER` (e as credenciais/configuração de webhook) vive no projeto Platform. `SUBSCRIBER` e `ENTITLEMENT` colapsam, fisicamente, na tabela `partner_subscribers` de cada projeto de produto; `EVENT` não é uma tabela — é o disparo do webhook na mudança dessas linhas. `USER`, `PROFILE`, `CHILD_PROFILE`, `NOVEL`, `CHAPTER` e `PAGE` vivem dentro dos projetos Supabase de cada produto — ver [Modelo multi-tenant](/architecture/multi-tenant-model) para onde exatamente cada um vive. # Modelo multi-tenant Source: https://developers.googa.com.br/architecture/multi-tenant-model Como o isolamento funciona em dois eixos independentes — entre parceiros que integram a mesma API, e entre produtos com sensibilidade de dado diferente. Esta página assume o [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model) como pré-requisito — em especial a seção "Isolamento multi-tenant — Row Level Security", que não repetimos aqui. O que segue detalha as duas decisões de isolamento que ficam *acima* de RLS: entre parceiros, e entre produtos. ## Dois eixos de isolamento, não um "Multi-tenant" nesta plataforma significa duas coisas diferentes, e é fácil confundi-las: 1. **Isolamento entre parceiros** — a Algar não pode ver, nem por acidente, dado de um segundo parceiro que venha a integrar depois. Esse é um problema *horizontal*: a mesma API, os mesmos produtos, múltiplos consumidores institucionais. 2. **Isolamento entre produtos** — o dado de uma criança no HistorinhAI não pode ter caminho de acesso, nem teórico, através de um bug ou de uma credencial comprometida no projeto que serve NovelAI/NovelÁudio. Esse é um problema *vertical*: sensibilidade de dado diferente exige raio de explosão (blast radius) diferente, independente de quantos parceiros existam. O mecanismo de isolamento entre **leitores individuais** dentro de um mesmo produto (um usuário não vê a linha de outro) já é resolvido por RLS e está fora do escopo desta página — ver [Modelo de autenticação](/architecture/supabase-auth-model). ## Isolamento entre produtos: por que a decisão foi diferente para cada caso NovelAI e NovelÁudio vivem no mesmo projeto Supabase ("Novel") desde o schema inicial. Isso não é um atalho — é a modelagem correta para o caso: os dois produtos servem o **mesmo catálogo** (a mesma novela, os mesmos capítulos, os mesmos finais — um em texto, outro narrado), e o conteúdo sensível em jogo é preferência de leitura de um adulto — dado pessoal, mas de baixa severidade se um bug de isolamento vazasse entre as duas superfícies do mesmo projeto. Historicamente uma conta podia assinar os dois produtos (mesmo login, mesma pessoa) — desde a introdução de `profiles.isolated_app`, todo cadastro NOVO fica isolado a um único app no momento do signup; só contas anteriores a essa mudança continuam com acesso aos dois. O motivo de compartilhar o projeto deixou de ser "a mesma pessoa assina os dois" e passou a ser puramente o catálogo compartilhado: os dois produtos vendem o mesmo conteúdo (texto vs. áudio), e não faria sentido manter duas cópias do mesmo grafo de novelas/capítulos/finais em projetos separados só porque cada conta agora só acessa um lado. A tabela `profiles` marca a origem com uma coluna `app_source` (`novelai` ou `novelaudio`) e, para contas novas, `isolated_app` trava o acesso a um único produto; a tabela `subscriptions` tem uma chave composta `(user_id, app)`, porque uma conta legada com acesso aos dois pode ter planos diferentes em cada um. RLS continua isolando usuário de usuário normalmente — o que **não existe** é isolamento de infraestrutura entre os dois produtos, porque não faz sentido operacional pagar esse custo por dois produtos que compartilham 100% do catálogo. **Trade-off aceito:** menos overhead operacional (uma migration, um Auth, um Storage, uma fatura) em troca de isolamento mais fraco entre os dois produtos — aceitável porque o dado em jogo tem o mesmo nível de sensibilidade nos dois lados. HistorinhAI roda em um projeto Supabase próprio, sem nenhuma tabela compartilhada com o projeto "Novel". Essa é uma decisão deliberada, e a razão não é técnica no sentido de "RLS não funcionaria" — RLS funcionaria perfeitamente bem isolando linha por linha mesmo dentro de um projeto compartilhado. A razão é de **defesa em profundidade** dado o tipo de dado: perfil de criança (nome, data de nascimento, preferências, relatório de desenvolvimento comportamental) sob o Estatuto da Criança e do Adolescente, além da LGPD (ver [Proteção de dados de menores](/security/child-data-eca)). Com projetos separados, uma política de RLS mal configurada, uma Edge Function com um bug, um `service_role` key vazado, ou uma ação administrativa equivocada no projeto "Novel" **não têm caminho algum** — nem teórico — até uma tabela com dado de criança, porque essa tabela não está no mesmo banco. Isso transforma uma classe inteira de incidentes de "prevenível por política, se ela estiver correta" para "estruturalmente impossível, independente de qualquer política". É também uma narrativa de conformidade muito mais simples para auditoria e DPO: "dado de criança vive no próprio banco, ponto" é mais fácil de defender e de auditar do que "dado de criança vive no mesmo banco, protegido por políticas de aplicação". **Trade-off aceito:** mais overhead operacional (dois Auth, dois Storage, duas faturas, duas superfícies de migration) em troca de um limite físico que não depende de nenhuma política estar certa. A regra geral por trás das duas decisões: **o custo de isolar sobe com o overhead operacional; o benefício de isolar sobe com a severidade do dado.** Quando os dois produtos compartilham nível de sensibilidade (NovelAI/NovelÁudio), o projeto compartilhado vence. Quando um produto lida com dado de criança, a defesa em profundidade justifica o custo adicional mesmo que RLS, isoladamente, já resolvesse o problema no papel. ## `partner_id`: isolando parceiros, não produtos O eixo de parceiro é ortogonal ao eixo de produto descrito acima, e vive em uma camada diferente: o projeto Supabase "Platform" (dedicado à API de parceiro, descrito em [Modelo de autenticação](/architecture/supabase-auth-model)) guarda `partners` e `partner_credentials` — estruturalmente preparado para múltiplos parceiros desde o schema inicial. O entitlement em si (a coluna `partner_id` junto do `subscriber_id`) vive do lado de cada **produto**, na tabela `partner_subscribers` do respectivo projeto — não em uma tabela do Platform. O isolamento entre parceiros **não** é feito por policy de RLS comparando `partner_id`: as tabelas do domínio de parceiro têm RLS habilitado com **zero policies** — nenhum acesso para `anon`/`authenticated`; só as Edge Functions do Partner Gateway, via `service_role`, leem e escrevem nelas. O filtro por parceiro acontece dentro dessas functions, sempre a partir do JWT de serviço verificado, nunca de um valor enviado na requisição: ```sql theme={null} -- padrão real das tabelas de domínio de parceiro (Platform e produtos) alter table public.partner_subscribers enable row level security; -- RLS habilitado, ZERO policies: só service_role (Edge Functions) acessa. ``` ```ts theme={null} // dentro da Edge Function: partner_id vem do token verificado, nunca do payload const claims = await requirePartnerToken(req, "subscriber:read"); supabase.from("partner_subscribers").select("...").eq("partner_id", claims.partnerId); ``` Isso isola um parceiro de outro com o mesmo rigor com que RLS isola um leitor de outro dentro de um produto — o mecanismo é diferente (verificação de JWT na function, em vez de policy por linha), mas a propriedade garantida é a mesma: nenhum caminho de acesso cruzado. Como NovelAI/NovelÁudio e HistorinhAI vivem em projetos Supabase separados do Platform, `partner_id` não pode ser uma foreign key de banco atravessando projetos — Postgres não tem FK entre instâncias diferentes. O limite é garantido pelo Partner Gateway: cada Edge Function de domínio (`entitlements-novelai`, `entitlements-historinhai`) valida a assinatura do JWT de serviço antes de aplicar sua própria lógica, e é essa validação — não uma constraint de banco — que impede um parceiro de agir sobre o `partner_id` de outro. Isso está descrito com mais detalhe na seção "Roteamento cross-projeto" do [Modelo de autenticação](/architecture/supabase-auth-model). ## Um segundo parceiro, sem mudança de schema Quando um parceiro além da Algar quiser integrar — outra operadora, um banco, um varejista — o modelo já está preparado para isso, porque o desenho não codificou "Algar" em nenhum lugar do schema: 1. **Nova linha em `partners`** (projeto Platform) — nome, escopos permitidos, status. 2. **Novo `partner_credentials`** — `client_id`/hash do `client_secret` para esse parceiro trocar por um JWT de serviço em `/oauth2/token`. 3. Cada entitlement, cada evento de billing usage, cada webhook desse parceiro nasce com o `partner_id` dele — as mesmas tabelas, as mesmas policies, sem alteração de estrutura. O que **muda** por parceiro não é schema — é configuração: escopos permitidos, limites de rate-limit na borda, e os termos comerciais/SLA específicos daquele contrato (que vivem fora do banco, no contrato em si). O mesmo vale no sentido inverso: um parceiro pode ativar qualquer subconjunto dos três produtos (só NovelAI, ou os três) sem exigir nenhuma tabela nova — `partner_id` mais o produto referenciado no entitlement já expressam essa combinação. O desenho descrito nesta página (ver [Modelo de autenticação](/architecture/supabase-auth-model)) já nasce pronto para múltiplos parceiros, mesmo antes do segundo parceiro existir. # Visão geral da arquitetura Source: https://developers.googa.com.br/architecture/overview O mapa de camadas da plataforma Googa e as decisões de engenharia por trás de cada peça. ## As camadas A plataforma Googa é composta por cinco camadas. A camada "API de parceiro" é a que esta documentação especifica; as outras quatro existem para dar suporte a ela, e já existiam antes dela — foram construídas para servir os apps oficiais (NovelAI, HistorinhAI, NovelÁudio) diretamente, e a API de parceiro se apoia nelas em vez de duplicá-las. ``` ┌───────────────────────────────────────────────────────────────────────────┐ │ EXPERIÊNCIA │ │ App NovelAI (Web/PWA) · App HistorinhAI (Web/PWA) · App NovelÁudio (Web/PWA) │ Web-view dentro do app do parceiro (ex: Minha Algar) │ ├───────────────────────────────────────────────────────────────────────────┤ │ API DE PARCEIRO ← esta documentação │ │ api.googa.com.br (Platform) — OAuth2 client credentials │ │ Entitlements · Subscriber Status · Billing Usage · Webhooks · SSO/OIDC │ ├───────────────────────────────────────────────────────────────────────────┤ │ SERVIÇOS DE DOMÍNIO (por produto; Edge Functions de parceiro já no código) │ │ Projeto "Novel" (NovelAI + NovelÁudio): catálogo, drip diário de │ │ capítulo, ramificação/finais, progresso de leitura e de escuta, │ │ TTS pré-renderizado, entitlement de streaming por assinatura │ │ Projeto "HistorinhAI": perfis de criança, geração personalizada, │ │ relatório mensal, streak/pontuação │ │ Implementado como Postgres RLS + RPC + Edge Functions — sem │ │ microsserviços separados │ ├───────────────────────────────────────────────────────────────────────────┤ │ DADOS │ │ Postgres com Row Level Security (um projeto Supabase por produto/grupo) │ │ Storage (áudio pré-renderizado, servido por signed URL de curta duração) │ ├───────────────────────────────────────────────────────────────────────────┤ │ SEGURANÇA & OBSERVABILIDADE │ │ RLS como controle de acesso primário · TLS 1.3 via Custom Domain │ │ Criptografia em repouso gerenciada pela infraestrutura do Supabase │ └───────────────────────────────────────────────────────────────────────────┘ ``` Os aprofundamentos de cada peça desta pilha estão em três páginas: Como identidade de parceiro, de assinante e de app convergem sobre Supabase Auth — e o papel exato do Custom Domain. Isolamento entre parceiros e entre produtos — RLS, `partner_id`, e por que a decisão de isolamento físico foi diferente para o HistorinhAI. O vocabulário da API: Subscriber, User, Reader/Listener, Novel/Chapter/Page, Entitlement, Event. ## Decisões de arquitetura A tabela abaixo documenta, camada por camada, as escolhas de engenharia por trás da stack — onde optamos por um componente gerenciado no lugar de operar infraestrutura própria, e por quê. ### Frontend | Componente | Escolha | Por quê | | ---------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | Web (PWA) | Vite + React, servido como PWA instalável | Deploy mais simples que um framework full-stack, com a mesma instalabilidade e suporte offline de um PWA | | Deep-links | Suportado pela estrutura de rotas do PWA por produto | Cobre o caso de uso sem depender de app nativo | ### Backend | Componente | Escolha | Por quê | | ----------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | | Lógica de negócio | Postgres RPC (`security definer`) e Supabase Edge Functions (Deno/TypeScript) — sem microsserviços separados | Menos componentes para operar; a regra de negócio fica perto do dado que ela protege | ### APIs | Componente | Escolha | Por quê | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | | Protocolo | REST — PostgREST (`/rest/v1`, gerado a partir do schema+RLS) e Edge Functions REST (`/functions/v1`) para lógica customizada | Cobre o caso de uso sem o custo de operar um segundo protocolo (GraphQL) em paralelo | | Especificação | OpenAPI 3.1 (ver `platform/openapi.yaml` e os specs por produto) | Formato padrão, gera a página de Referência automaticamente | | Autenticação de sistema | OAuth2 client credentials (ver [Modelo de autenticação](/architecture/supabase-auth-model)) | Padrão RFC 6749 para integração servidor-a-servidor | | Versionamento | Convenção `/v1` no path | Espaço para uma mudança de contrato futura sem quebrar integrações existentes | ### Dados | Componente | Escolha | Por quê | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | Banco relacional | Postgres (Supabase), um projeto por produto/grupo de produtos | Cobre 100% dos casos de uso atuais sem um segundo RDBMS | | Cache | Sem cache dedicado — connection pooling (PgBouncer) já embutido no Supabase | Cobre o volume atual sem operar Redis | | Storage de arquivo | Supabase Storage (compatível com a API S3), buckets privados com signed URL | Equivalente gerenciado ao S3, sem infraestrutura própria | | Eventos | Postgres `LISTEN/NOTIFY` + Database Webhooks (trigger `pg_net`) — ver [Modelo de autenticação](/architecture/supabase-auth-model) | Cobre o volume de eventos de parceiro sem Kafka/broker separado | | Busca | Full-text nativa do Postgres | O catálogo atual não justifica um motor de busca dedicado | ### IA/ML | Componente | Escolha | Por quê | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- | | Modelo de linguagem | Modelos de terceiros via API, com prompt/RAG próprio sobre o cânone de cada obra | Sem o custo de manter fine-tuning/infraestrutura de treino próprios | | Similaridade de obras | Tags/categoria editorial | Cobre a curadoria atual sem o custo de manter um índice vetorial | | TTS / áudio | Provedor terceiro; a narração do NovelÁudio é áudio pré-renderizado por capítulo (não gerado a cada play), servido por signed URL — decisão técnica de anti-pirataria documentada nas migrations do projeto "Novel" (repo do NovelAI, que os dois produtos compartilham) | Evita custo de TTS por play e reduz superfície de pirataria | | Guardrails de conteúdo | Curadoria editorial humana | O volume atual de catálogo é bem servido por revisão humana direta | ### Infra | Componente | Escolha | Por quê | | ------------------- | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | Hospedagem do banco | Infraestrutura gerenciada do Supabase — Postgres com multi-AZ e failover automático nativos | Mesma disponibilidade que operar containers próprios, com menos partes móveis | | Schema como código | Migrations SQL versionadas em Git | Não há infraestrutura de containers para provisionar via Terraform | | Autoscaling | Nativo da infraestrutura gerenciada (Postgres + Edge Functions escalam sem operação manual) | Sem operação manual de capacidade | | CDN | Build estático do PWA servido via CDN | Distribuição global sem infraestrutura própria | O Supabase entrega Postgres replicado, failover automático e backups criptografados com point-in-time recovery como parte gerenciada da plataforma, sem que a Googa precise operar um control plane Kubernetes, uma malha de rede entre pods, ou o pipeline de IaC que sustentaria tudo isso. Isso é a mesma disponibilidade com menos partes móveis, o que **reduz** superfície de falha operacional em vez de aumentá-la, e libera o tempo de engenharia que seria gasto operando infraestrutura para o que de fato diferencia o produto — o pipeline editorial, a personalização e a segurança de dados infantis do HistorinhAI. Se o volume de tráfego ou um requisito contratual específico (ex: residência de dados em ambiente dedicado) justificar migrar uma peça específica para containers próprios, isso é uma decisão pontual sobre um componente, não uma reescrita da plataforma. ### DevEx | Componente | Escolha | Por quê | | -------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | CI/CD | GitHub Actions — migrations e deploy de Edge Functions passam por pipeline | Aplica mudança de schema/função de forma consistente e auditável | | Testes automatizados | Cobertura concentrada nas regras de negócio mais sensíveis (drip, entitlement, limites) | Prioriza o que quebra silenciosamente e é caro de detectar manualmente | ### Segurança | Componente | Escolha | Por quê | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | Gestão de chaves (KMS) | Gerenciado pela infraestrutura do Supabase | Sem operação própria de rotação/custódia de chave | | TLS | 1.3, inclusive sob Custom Domain (`api.novelai.com.br` etc.) | Padrão atual, nativo do Supabase | | mTLS interno | Não aplicável — não há malha de microsserviços internos para proteger; Edge Functions falam com Postgres via conexão gerenciada | — | | RBAC/ABAC | RLS por linha do Postgres | Controle mais granular que RBAC de papel — cada política é avaliada por linha, não por papel amplo | # Modelo de autenticação sobre Supabase Source: https://developers.googa.com.br/architecture/supabase-auth-model Como identidade de leitor, identidade de parceiro e domínio customizado se combinam em cima do Supabase. ## Por que isso não é trivial Cada produto Googa hoje é servido por um projeto [Supabase](https://supabase.com) — Postgres com Row Level Security (RLS), Supabase Auth e Edge Functions. Isso resolve muito bem **um** problema: autenticar o usuário final (o leitor) dentro do próprio app oficial. A API de parceiro precisa resolver um problema diferente e mais amplo: 1. **Duas identidades, não uma.** O parceiro (ex: o backend da Algar) autentica como *sistema*, não como pessoa — client credentials, sem sessão de navegador. O assinante final autentica como *pessoa*, via SSO federado pelo "Minha Algar". São dois fluxos de auth completamente diferentes que convergem na mesma API. 2. **Multi-projeto.** NovelAI e NovelÁudio já compartilham um projeto Supabase; HistorinhAI roda em outro, isolado — decisão deliberada, dado o tratamento de dados de crianças (ver [Proteção de dados de menores](/security/child-data-eca)). A API de parceiro precisa apresentar uma superfície única em três domínios — `api.googa.com.br`, `api.novelai.com.br` (que também atende o NovelÁudio) e `api.historinhai.com.br` — sem expor essa fragmentação para quem integra. Não existe `api.novelaudio.com.br` (ver [NovelÁudio](/novelaudio/overview)). 3. **Domínio próprio, não `*.supabase.co`.** Nenhum parceiro enterprise aceita apontar para o domínio de um fornecedor de infra. O desenho usa `api.novelai.com.br`, `api.historinhai.com.br` e `api.googa.com.br`, com TLS e sem redirect visível. ## Capacidades nativas do Supabase O plano Supabase Pro (e superiores) inclui **Custom Domains**: você aponta um `CNAME` do seu domínio para `.supabase.co`, o Supabase provisiona e renova o certificado TLS automaticamente, e a partir daí tanto PostgREST (`/rest/v1`) quanto Edge Functions (`/functions/v1`) e Auth (`/auth/v1`) passam a responder sob o domínio próprio. Para os três domínios de API, isso significa: `api.novelai.com.br` é o **único** backend físico tanto para NovelAI quanto para NovelÁudio — os dois apps já compartilham o mesmo projeto Supabase hoje ("Novel"), então não faz sentido criar um `api.novelaudio.com.br` separado só para bater na mesma infraestrutura; a Edge Function resolve por rota/recurso (texto vs. áudio), não por domínio. `api.historinhai.com.br` aponta para o projeto Supabase próprio do HistorinhAI — isolado de propósito. `api.googa.com.br` (Platform API) usa um projeto Supabase dedicado, só para a camada de parceiro — ver [Multi-tenant](/architecture/multi-tenant-model). ``` api.novelai.com.br ────▶ CNAME ──▶ Projeto Supabase "Novel" () atende NovelAI (texto) e NovelÁudio (áudio) api.historinhai.com.br ────▶ CNAME ──▶ Projeto Supabase "HistorinhAI" () api.googa.com.br ────▶ CNAME ──▶ Projeto Supabase "Platform" (dedicado à API de parceiro) ``` **Planejado — ainda não implementado: nenhum IdP de parceiro está configurado hoje.** Supabase Auth suporta provedores OIDC customizados (além dos sociais padrão). Para o fluxo "login federado pelo Minha Algar, sem nova senha", o desenho correto é: **o Minha Algar é o Identity Provider (IdP)**, e o Supabase Auth de cada produto atua como **Relying Party (RP)** — exatamente o papel para o qual foi construído. Fluxo (`/oauth2/authorize` do lado da Algar): 1. O assinante toca "Ler novela" dentro do app Minha Algar. 2. Minha Algar redireciona para `api.novelai.com.br/auth/v1/authorize?provider=algar` (endpoint nativo do Supabase Auth, configurado com o Client ID/Secret do provedor OIDC da Algar). 3. Supabase Auth troca o `authorization_code` pelo `id_token` da Algar, valida a assinatura, e cria (ou recupera) o usuário Supabase correspondente — o `sub` do token da Algar fica gravado em `auth.identities`, e o `subscriber_id` da Algar vai para `app_metadata`. 4. O app recebe uma sessão Supabase normal (JWT `access_token`/`refresh_token`) — daqui em diante, RLS funciona exatamente como para um usuário que criou conta com e-mail/senha. Isso é **configuração**, não código novo — o esforço real está do lado da Algar expor um endpoint OIDC padrão, e do nosso lado mapear `app_metadata.algar_subscriber_id` nas políticas de RLS que hoje já usam `auth.uid()`. Os eventos que o parceiro precisa (`subscriber.updated`, `subscription.canceled`) nascem de mudanças na tabela de entitlements de parceiro. Supabase tem **Database Webhooks** nativos: um trigger Postgres (`pg_net`) dispara uma chamada HTTP assíncrona sempre que uma linha muda. O desenho implementado encadeia isso a uma função intermediária de despacho (`webhook-dispatch`, projeto Platform), que assina o payload com HMAC-SHA256 (`X-Googa-Signature`, `X-Googa-Event`) e entrega ao `webhook_url` do parceiro em **uma única tentativa** — o retry nativo do Database Webhook cobre falha ao invocar a função de despacho, mas **não existe fila própria de reentrega** ao endpoint do parceiro. Não precisa de Kafka nem de um broker separado para o volume de eventos de um parceiro de billing — é a ferramenta certa para o tamanho do problema. Ver a verificação de assinatura em [Platform API — Eventos](/platform/overview#eventos-webhooks-de-saída). RLS já é a linha de defesa principal hoje (cada leitor só vê as próprias linhas). Para a API de parceiro, o desenho implementado é diferente do RLS por política do leitor: as tabelas de domínio de parceiro (`partners`, `partner_credentials`, `partner_subscribers`...) têm RLS **habilitado com zero policies** — nenhum acesso por `anon`/`authenticated`; só as Edge Functions do Partner Gateway, via `service_role`, as tocam. O isolamento entre parceiros é aplicado dentro dessas functions: toda consulta filtra pelo `partner_id` extraído do JWT de serviço verificado — nunca por um valor enviado pelo cliente na própria requisição. Ver [Modelo multi-tenant](/architecture/multi-tenant-model). ## Partner Gateway — a camada que conecta as duas pontas Supabase **não** oferece, nativamente, um servidor de autorização OAuth2 para emitir credenciais *a outros sistemas* (client credentials grant) — ele é um IdP para pessoas, não uma central de emissão de chaves de API para máquinas. Isso é esperado: nenhum BaaS genérico resolve isso, porque é uma decisão de produto, não de infraestrutura. O Partner Gateway é a camada fina construída por cima para resolver exatamente isso. Um projeto Supabase dedicado ("Platform") guarda `partners` (com `webhook_url`/`webhook_secret` de cada parceiro), `partner_credentials` (client\_id, hash do client\_secret, escopos permitidos, status) e `partner_api_keys` (chave rotacionável para leituras simples — a tabela existe, mas a verificação por API key ainda **não** está implementada em nenhum endpoint). Nenhum dado de leitor mora aqui — só metadado de integração. Uma Edge Function em `api.googa.com.br/oauth2/token` implementa o grant `client_credentials` do OAuth2 (RFC 6749 §4.4): recebe `client_id` + `client_secret`, valida contra `partner_credentials`, e devolve um JWT assinado com os escopos do parceiro e TTL curto (10 minutos). Esse JWT é o que autentica as chamadas seguintes a Entitlements/Billing — ele nunca é um JWT de usuário Supabase, é um JWT de **serviço**, verificado pelas outras Edge Functions via a chave pública do projeto Platform. Como NovelAI/NovelÁudio e HistorinhAI vivem em projetos Supabase diferentes, o Partner Gateway (projeto Platform) não acessa os dados diretamente — ele chama as Edge Functions de domínio de cada produto (`entitlements-novelai`, `entitlements-historinhai`) passando o JWT de serviço junto, e cada produto valida esse JWT contra a chave pública do Platform antes de aplicar sua própria lógica de RLS/negócio local. Isso mantém o isolamento entre produtos sem duplicar a lógica de autenticação de parceiro em cada projeto. **Exceção deliberada (planejada — ainda não implementada) — HistorinhAI emitir a própria credencial.** Para o produto que trata dados de crianças, o desenho de destino vai um passo além: `api.historinhai.com.br` teria seu próprio emissor de token e seu próprio par de chaves de assinatura, independentes do Platform Gateway, servindo o futuro endpoint de engajamento (ver [API HistorinhAI](/historinhai/overview)). **Hoje isso não existe**: o HistorinhAI valida o token emitido pelo Platform (mesma chave pública), e o emissor próprio foi deliberadamente adiado para uma revisão dedicada. Quando existir, será *defesa em profundidade*: um comprometimento da chave de assinatura do Platform não dá acesso a nenhuma credencial do HistorinhAI, e vice-versa — ao custo de um cadastro de credencial duplicado por parceiro, um trade-off aceito dado o que está em jogo nesse produto especificamente. Nem PostgREST nem Edge Functions têm rate-limit configurável por parceiro/rota fora do que o Supabase já aplica para proteção própria da plataforma. A camada de rate-limit por parceiro (e WAF) fica na borda, antes do Custom Domain — um proxy leve (Cloudflare na frente do CNAME é a opção mais simples: regras de rate-limit por token de API, sem mudar nada do lado do Supabase). ## Resumindo: quem autentica o quê | Ator | Como autentica | Onde isso é validado | | ----------------------------------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | | Leitor final (app oficial) | Supabase Auth (e-mail/senha, ou SSO Algar) → JWT de usuário | RLS no projeto do produto | | Sistema do parceiro (server-to-server) | OAuth2 client credentials → JWT de serviço de curta duração | Partner Gateway (projeto Platform) valida; produto valida a assinatura | | Webhook de saída (Googa → parceiro) | Assinatura HMAC do payload (`X-Googa-Signature`) | Verificado pelo receptor (parceiro) | | Chamada simples de leitura via API key estática | *Planejado — não implementado* (a tabela de chaves existe; a verificação, não) | Partner Gateway (quando existir) | Nenhuma dessas quatro linhas exige trocar o Supabase por outra coisa — todas são construídas **em cima** do que já existe, com uma única peça nova (o Partner Gateway) fazendo a ponte entre "autenticação de máquina" e o modelo de "autenticação de pessoa" que o Supabase já resolve bem. # HistorinhAI API — visão geral Source: https://developers.googa.com.br/historinhai/overview A API de parceiro do HistorinhAI é deliberadamente pequena: nenhum dado identificável de criança sai do perímetro do produto. Isso é regra de arquitetura, não uma limitação técnica. Hoje só o app oficial (Web/PWA — não há apps nativos) consome o HistorinhAI, autenticando diretamente contra o projeto Supabase do produto. Esta página descreve o contrato para um parceiro (ex: uma operadora) integrar sem acesso direto ao banco de dados de crianças. ## Por que esta API é bem menor que NovelAI/NovelÁudio Isso não é um contrato incompleto — é o tamanho correto para o problema. O HistorinhAI trata dados de crianças, e a proposta técnica original à Algar já assume essa restrição explicitamente na seção de segurança: *"dados da criança sob responsabilidade dos pais, sem perfilamento comercial de menores"* (Proteção infantil — ECA). Levamos essa frase a sério como **regra de arquitetura**, não como intenção de marketing: o desenho abaixo assume, desde o primeiro endpoint, que nenhum parceiro externo — mesmo um parceiro contratual como a Algar, mesmo com consentimento parental válido para o app funcionar — recebe dado identificável de uma criança individual. Repassar isso a um terceiro é uma superfície de risco de LGPD (Lei 13.709/2018) e do Estatuto da Criança e do Adolescente (Lei 8.069/1990) que nenhum ganho comercial de integração justifica. Consequência prática: a integração de parceiro no HistorinhAI resolve **apenas** dois problemas — "o assinante tem direito de acesso?" (Entitlements, já coberto pela [Platform API](/platform/overview) e não repetido aqui) e "como está o engajamento agregado da minha base neste produto?" (um único endpoint de métrica, sem granularidade de criança, ainda **planejado** — ver abaixo). Não há endpoint de catálogo, de perfil de criança, de progresso individual, de relatório ou de conteúdo. Se uma futura necessidade comercial exigir mais do que isso, o desenho correto é resolvê-la dentro do app oficial (onde o responsável está autenticado e no controle), não abrir uma nova rota nesta API — ver [O que esta API deliberadamente não expõe](#o-que-esta-api-deliberadamente-não-expõe). ## Isolamento de dados e infraestrutura `api.historinhai.com.br` aponta para um projeto [Supabase](https://supabase.com) **próprio**, isolado do projeto que atende NovelAI e NovelÁudio — decisão deliberada, não uma consequência acidental de como o produto foi construído. Ver [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model#capacidades-nativas-do-supabase) para o desenho completo de domínios; o ponto relevante aqui é que esse isolamento é a primeira camada de defesa por trás de tudo nesta página — mesmo que a credencial de parceiro de outro produto Googa fosse comprometida, ela não teria como alcançar o banco de dados do HistorinhAI, porque é fisicamente outro projeto, com outra base de dados e outro conjunto de chaves. Hoje a credencial de parceiro que o HistorinhAI reconhece é a emitida centralmente pela [Platform API](/platform/overview#autenticação); um emissor próprio, sob este domínio e com par de chaves independente, é **planejado — ainda não implementado** — ver [Autenticação](#autenticação) abaixo. ## O que esta API oferece Hoje: o token vem do emissor central da [Platform API](/platform/overview#autenticação) (`POST https://api.googa.com.br/v1/oauth2/token`). Um `POST /oauth2/token` próprio deste domínio, escopado a `historinhai:engagement:read`, é **planejado — ainda não implementado**. `GET /engagement/summary` — **planejado, ainda não implementado**: contas ativas, histórias concluídas e minutos médios por conta ativa (`avg_minutes_per_active_account`) no período, agregado sobre **toda** a base do parceiro. Sem lista, sem linha por conta, sem linha por criança. Ver [Referência](/historinhai/reference) para o contrato completo. Isso é tudo. Qualquer outra necessidade de integração do parceiro com o HistorinhAI — ativar acesso, verificar status de assinante, reportar uso para billing, autenticar o assinante via SSO — já está coberta pela [Platform API](/platform/overview), que é a mesma para os três produtos e não trata dado de criança em nenhum momento (o `subscriber_id` ali é o identificador do **responsável**, no sistema do parceiro). ## O que esta API deliberadamente não expõe Esta seção é tão importante quanto a anterior. Cada item abaixo foi considerado e excluído por uma razão específica — não por falta de tempo de desenho. O app mantém, por criança, nome, data de nascimento e um avatar escolhido pelos pais (perfil gerido dentro de uma conta-família, com até 6 crianças). Nenhum desses campos tem contrapartida em qualquer endpoint desta API. Um parceiro nunca tem motivo de negócio legítimo para saber o nome ou a idade exata de uma criança específica — só se ela tem, na agregada, uma conta com acesso ativo, o que já é resolvido pelo Entitlements da Platform API no nível do responsável. Texto literal de histórias, respostas do mini-desafio lúdico (quiz/conversa guiada) e qualquer transcrição de interação da criança com o app não têm — e não terão — um endpoint de leitura para parceiro. Isso é conteúdo de uma interação privada entre a criança, o responsável e o app; expor isso a um terceiro comercial não passa o teste de finalidade da LGPD (a finalidade da coleta é a experiência de leitura em si, não telemetria de terceiro). Sequência de leitura, pontos, minutos lidos e o relatório de desenvolvimento que o app entrega aos pais (histórias lidas, tempo compartilhado, competências percebidas) existem para o responsável dentro do próprio app — nunca como resposta de API para um parceiro. Isso vale mesmo agregado por criança ao longo do tempo: um parceiro que conseguisse reconstruir a trajetória de leitura de uma criança específica teria, na prática, um perfil comportamental de um menor — exatamente o que a cláusula de "sem perfilamento comercial de menores" da proposta técnica existe para impedir. O app registra quem participou de cada sessão de leitura (a própria criança, um responsável, outro membro da família) para alimentar estatísticas de uso compartilhado dentro do app. Esse detalhe por sessão nunca é individualmente endereçável via API de parceiro — só entra, sem identificação de sessão ou de criança, no agregado de `stories_completed` do endpoint de engajamento. Quantos adultos compõem uma conta-família, quem é o responsável principal e convites pendentes são informação de gestão de conta dentro do app — não fazem parte de nenhum contrato de parceiro. Do ponto de vista do parceiro, uma conta-família é só uma unidade anônima que conta para `active_accounts`. Deliberadamente **sem** endpoint de catálogo — diferente de NovelAI/NovelÁudio, onde listar o catálogo para o parceiro tem uma razão de negócio clara (o parceiro pode querer promover títulos). No HistorinhAI não identificamos uma razão de negócio equivalente: a curadoria por faixa etária e por desafio do mês é parte do valor do produto e permanece uma decisão editorial interna, exercida dentro do app, sob supervisão dos pais. Expor externamente o mapeamento entre título e faixa etária também aumentaria, ainda que marginalmente, o risco de combinação com dados de uso agregados para inferir características de uma criança — risco que não compensa o ganho de expor um catálogo que o parceiro não tem como comercializar por conta própria. `GET /engagement/summary` aceita apenas uma janela de tempo como parâmetro. Não existe, e não está desenhada, uma versão com `subscriber_id`, `family_id` ou `child_id` como filtro — isso transformaria um agregado seguro em uma consulta pontual sobre uma família específica. O piso mínimo de amostra (`min_sample_threshold`, 30 contas ativas no desenho) documentado na [Referência](/historinhai/reference) de `GET /engagement/summary` existe pelo mesmo motivo: impedir que um corte de período pequeno demais funcione como um jeito indireto de isolar uma conta. ## Autenticação Toda chamada usa OAuth2 **client credentials**, o mesmo grant da [Platform API](/platform/overview#autenticação). **Hoje**, a credencial vem do emissor central da Platform (`POST https://api.googa.com.br/v1/oauth2/token`) — o HistorinhAI valida o token recebido contra a chave pública do projeto Platform, e é assim que o endpoint interno de entitlements (roteado pela Platform) funciona no código. Um emissor **próprio** deste domínio (`POST /oauth2/token` em `api.historinhai.com.br`, com par de chaves independente e escopo único `historinhai:engagement:read`) é **planejado — ainda não implementado**: foi deliberadamente adiado para uma revisão dedicada, por ser o produto que trata dado de criança. Ver [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model) para o racional de defesa em profundidade por trás desse desenho. ## Proteção de dados de crianças O raciocínio de compliance por trás de cada exclusão listada acima — a base legal na LGPD e no ECA, como o consentimento parental é obtido e mantido dentro do app, e como isso se relaciona com as práticas de segurança da informação da Googa — está documentado em [Proteção de dados de menores (ECA)](/security/child-data-eca). Esta página descreve o **quê** a API não expõe; aquela descreve o **porquê** legal e operacional com mais profundidade. # Métrica de engajamento agregada do período, sem granularidade de criança — planejado Source: https://developers.googa.com.br/historinhai/reference/engagement/métrica-de-engajamento-agregada-do-período-sem-granularidade-de-criança-—-planejado /historinhai/openapi.yaml get /engagement/summary **Planejado — ainda não implementado.** Este endpoint (e o Partner Gateway próprio e isolado que o servirá) foi deliberadamente adiado para uma revisão dedicada, dado o tratamento de dado de criança. O contrato abaixo é o desenho de destino. Retorna contagens agregadas no nível de **conta do parceiro como um todo** — nunca por criança, nunca por família individual, nunca com nome. Pensado para alimentar o painel de KPIs do parceiro (contas ativas, histórias concluídas no período) sem que nenhum dado identificável de menor deixe o perímetro do HistorinhAI. Ver [O que esta API deliberadamente não expõe](/historinhai/overview#o-que-esta-api-deliberadamente-não-expõe) para a justificativa completa de design. **Piso mínimo de amostra (k-anonimato).** Para evitar que um corte pequeno vire uma forma indireta de identificar uma família específica, a resposta suprime os campos numéricos (retorna `null`) sempre que `active_accounts` no período consultado fica abaixo de `min_sample_threshold` (hoje 30). Isso é deliberado mesmo sabendo que reduz a utilidade do endpoint em pilotos pequenos — um piloto de dezenas de milhares de usuários deve operar bem acima desse piso na maior parte dos recortes de período. Não aceita filtro por `subscriber_id`, por `child_id`, nem por qualquer outro identificador individual — o único parâmetro de recorte é a janela de tempo. # Troca client credentials por um token escopado ao HistorinhAI — planejado Source: https://developers.googa.com.br/historinhai/reference/oauth2/troca-client-credentials-por-um-token-escopado-ao-historinhai-—-planejado /historinhai/openapi.yaml post /oauth2/token **Planejado — ainda não implementado.** Hoje o HistorinhAI **não** emite token próprio: a única credencial de parceiro que ele reconhece é o token emitido pela Platform API (`POST https://api.googa.com.br/v1/oauth2/token`, ver [Platform — OAuth2](/platform/reference/oauth2/troca-client-credentials-por-um-token-de-acesso-de-parceiro)), verificado neste projeto com a chave pública do Platform. Este emissor próprio foi deliberadamente adiado para uma revisão dedicada, dado o que está em jogo no produto que trata dado de criança. Quando existir: mesmo grant `client_credentials` do OAuth 2.0 (RFC 6749 §4.4) da Platform API, exposto sob o domínio próprio do HistorinhAI — defesa em profundidade, não duplicação acidental: a credencial emitida aqui só carregará escopos deste produto, com par de chaves próprio, de modo que comprometer uma credencial de NovelAI/NovelÁudio não dê acesso a este endpoint, e vice-versa. O único escopo definido no desenho é `historinhai:engagement:read` — não há escopo de escrita, porque não há endpoint de escrita nesta API. # Googa Developers Source: https://developers.googa.com.br/index APIs para integrar NovelAI, HistorinhAI e NovelÁudio como SVA (Serviço de Valor Agregado) em operadoras e parceiros de distribuição. ## O que é a plataforma Googa A Googa opera três produtos editoriais nativos de IA — **NovelAI** (novela seriada para adultos), **HistorinhAI** (histórias infantis com personagem fixo, selecionadas por perfil e objetivo de desenvolvimento) e **NovelÁudio** (audiolivro seriado com narração neural). Os três compartilham o mesmo modelo de negócio — um capítulo novo por dia, sessões de 5 a 10 minutos — e o mesmo modelo de parceria: um parceiro (operadora de telecom, banco, varejista) integra uma vez e ativa qualquer combinação dos três como benefício ou SVA premium na própria fatura ou app. A escolha de final no último capítulo é exclusiva do NovelAI — HistorinhAI e NovelÁudio têm desfecho único e fixo por história. Esta documentação é o contrato técnico entre a Googa e quem integra: como autenticar, como provisionar acesso por assinante, como receber eventos, e como tratamos dados pessoais — incluindo dados de crianças no HistorinhAI. O que já está implementado e o que ainda é desenho planejado está marcado explicitamente em cada página. Como a identidade do parceiro, do assinante e do app se combinam — e o papel exato do Supabase nisso. Entitlements, status de assinante, uso para billing e webhooks — os endpoints compartilhados por todo parceiro. Criptografia, isolamento multi-tenant, base legal por finalidade, e o tratamento reforçado de dados de menores no HistorinhAI. ## Como ler esta documentação Os produtos rodam sobre projetos [Supabase](https://supabase.com) — Postgres com Row Level Security, autenticação e Edge Functions: NovelAI e NovelÁudio **compartilham** o projeto "Novel", e o HistorinhAI roda em um projeto próprio, isolado (ver [Modelo multi-tenant](/architecture/multi-tenant-model)). Cada projeto é consumido diretamente pelos apps oficiais (Web/PWA — não existem apps nativos iOS/Android hoje). O que este documento especifica é a camada que estende esse modelo para um sistema externo, como o de uma operadora: como ele provisiona acesso, recebe eventos e reconcilia billing, sem nunca tocar diretamente no banco de dados dos produtos. ## Os três produtos, uma superfície de API | Produto | Domínio | Público | O que a API de parceiro expõe | | -------------------- | ------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Platform** (comum) | `api.googa.com.br` | Todo parceiro | Entitlements, status de assinante, billing usage, webhooks; SSO é planejado | | **NovelAI** | `api.novelai.com.br` | Leitores adultos | Catálogo, progresso de leitura, capítulos liberados, escolhas de final, engajamento agregado | | **NovelÁudio** | `api.novelai.com.br` (mesmo backend) | Ouvintes | Catálogo de áudio, streaming, posição de reprodução (catálogo de vozes é roadmap — não existe hoje) | | **HistorinhAI** | `api.historinhai.com.br` | Famílias | **Somente** engajamento agregado e anonimizado — nenhum dado identificável de criança (perfis, geração e relatórios vivem só dentro do app; ver [HistorinhAI](/historinhai/overview)) | NovelAI e NovelÁudio compartilham o mesmo projeto Supabase e o mesmo backend físico — `api.novelai.com.br` atende as duas superfícies (a Referência de API de cada produto continua documentada em aba própria, porque os recursos são diferentes: um é texto, o outro é áudio). HistorinhAI roda em um projeto Supabase isolado — decisão deliberada dado o tratamento de dados de crianças — e por isso tem domínio próprio. # NovelAI API — visão geral Source: https://developers.googa.com.br/novelai/overview Catálogo, capítulos liberados pelo drip diário, progresso de leitura e finais ramificados — a API específica de produto do NovelAI. Hoje o catálogo, os capítulos e o progresso de leitura do NovelAI são consumidos diretamente pelo app oficial (Web/PWA — não há apps nativos) contra o projeto Supabase "Novel", via Row Level Security. Esta página e a [Referência de API](/novelai/reference) descrevem o contrato para um sistema terceiro ler esses dados sem acesso direto ao banco. A API do NovelAI é específica de produto: catálogo, capítulos, progresso de leitura e finais. Ela **não** repete Entitlements, Billing ou SSO — isso é resolvido uma única vez pela [Platform API](/platform/overview), comum a todos os produtos Googa. Um parceiro integrando o NovelAI usa a Platform API para saber *quem pode acessar* e *quanto cobrar*, e a API descrita aqui para saber *o que o assinante está lendo*. ## O modelo de conteúdo Cada novela é uma série fechada de **7 capítulos de conteúdo**, e cada capítulo tem **7 páginas de leitura** liberadas juntas — o drip controla o capítulo, não a página. O desfecho é um **capítulo final próprio** (o 8º em `novel_chapters`, só metadado — a tela de escolha de final, sem páginas de conteúdo), liberado **no mesmo dia** em que o 7º capítulo libera — o leitor não espera um dia a mais pelo final. `novel_pages` guarda o conteúdo com granularidade de página (`chapter_number` + `page_in_chapter`) e `novel_chapters` guarda o metadado por capítulo (título, duração estimada) usado tanto pelo menu de leitura quanto pelo player de áudio do NovelÁudio. O relógio do drip começa a contar quando o assinante abre a novela pela primeira vez — não na publicação da obra. A partir daí, um novo capítulo (7 páginas) libera a cada 06:00 (horário de Brasília). Isso é calculado sob demanda por uma função no banco (`unlocked_chapter_count`), não é um valor armazenado — não existe uma coluna "capítulos liberados" que possa ficar desatualizada, porque ela nunca existiu; o número é recalculado a cada leitura. Um assinante em qualquer plano com o benefício "acesso antecipado" (vendido hoje só no plano VIP do NovelÁudio, mas o mecanismo é do NovelAI) enxerga o capítulo seguinte um dia antes dos demais — a mesma função de drip soma 1 ao resultado quando detecta esse benefício ativo. Os finais (`novel_choices`) vivem em um capítulo final próprio, sem conteúdo de páginas — só a escolha de desfecho — liberado junto com o 7º capítulo, no mesmo dia. Eles só ficam visíveis — mesmo para o próprio assinante — quando esse capítulo libera. A API de parceiro reproduz exatamente essa regra: `GET /novels/{id}/choices` devolve `available: false` até lá. Um leitor não pode manter mais de 3 novelas simultaneamente em andamento (não finalizadas) — aplicado no servidor, não é uma regra só de UI. Terminar uma novela (escolher um final) ou removê-la de "Continuar lendo" libera a vaga. Nenhuma dessas regras muda para o parceiro: a API não oferece um jeito de "pular a fila" ou ver um capítulo antes da hora para um assinante que não tem o benefício — o parceiro vê exatamente o que o assinante veria no app oficial, no mesmo instante. Uma nota de honestidade: existem mecanismos internos, do lado do servidor, que liberam o catálogo inteiro para fins de demonstração e teste (modo demo do ambiente, contas internas de teste e liberações pontuais por obra) — eles não são expostos por esta API nem contratáveis por parceiro; citamos para que "não há bypass" não seja lido como "não existe nenhum mecanismo de bypass no sistema". ## Recursos `GET /categories`, `GET /novels`, `GET /novels/{id}` — metadados de catálogo: título, sinopse, categoria, tags editoriais, contagem de capítulos e se existe edição em áudio. `GET /novels/{id}/chapters` — metadado editorial de cada capítulo e, com `subscriber_id`, o estado de liberação (drip) daquele assinante especificamente. `GET /subscriber/{id}/reading-progress` — capítulo atual, capítulos liberados e novelas em andamento de um assinante, respeitando o limite de 3 ativas. `GET /novels/{id}/choices` — os até 4 desfechos de uma novela, só quando o drip já liberou o último capítulo para aquele assinante. `GET /analytics/engagement` — leitores ativos, taxa de conclusão e distribuição de finais escolhidos, sempre agregado por parceiro/período. Depende de `partner_id` por leitor — ver a [Referência de API](/novelai/reference) para o pré-requisito. `novel.finished` dispara quando um assinante escolhe um final. Não existe (e não é trivial de construir) um webhook de "capítulo liberado" — o drip é calculado, não é uma escrita; ver a nota na Referência de API. **Lacuna conhecida — capas do catálogo.** `NovelSummary.cover_image_url` está desenhado no contrato, mas hoje sempre retorna `null`: as \~112 capas do catálogo são assets estáticos embutidos no build do app oficial (`src/data/covers.ts`), não arquivos servidos por um bucket ou CDN. Um parceiro que queira renderizar o catálogo com capas reais (o caso de uso mais provável desta API) precisa que isso seja resolvido primeiro — migrar as capas para o Supabase Storage (ou um CDN próprio) é um pré-requisito não desenhado ainda, não apenas um campo pendente de implementação. ## Autenticação Toda chamada de servidor-a-servidor usa OAuth2 **client credentials**, com escopos próprios do NovelAI (`novelai:catalog:read`, `novelai:chapters:read`, `novelai:progress:read`, `novelai:choices:read`, `novelai:analytics:read`) — mas o token é emitido **uma única vez**, de forma centralizada, pela Platform API (`POST https://api.googa.com.br/v1/oauth2/token`), com esses mesmos escopos incluídos na mesma troca. Este domínio (`api.novelai.com.br`) só valida o token — via a chave pública do projeto Platform — nunca emite um token próprio; isso evita duplicar a verificação de credenciais em três projetos Supabase diferentes. Ver [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model) para o desenho completo do Partner Gateway e do roteamento cross-projeto. Para o caso mais simples e de menor risco — leitura pública de catálogo, sem dado de nenhum assinante — está **planejada** (ainda não suportada: nenhum endpoint verifica esse header hoje) uma alternativa de API key estática (`X-Googa-Api-Key`), restrita ao escopo `novelai:catalog:read`. ## Domínio ``` https://api.novelai.com.br/v1 ``` Este é o mesmo domínio/backend que atende o NovelÁudio (os dois produtos compartilham o projeto Supabase "Novel") — a Edge Function resolve o recurso pela rota, não pelo domínio. Os recursos específicos de áudio (streaming, posição de reprodução) estão documentados na aba [NovelÁudio](/novelaudio/overview), não aqui, ainda que fisicamente sejam a mesma API. Ver [Os três produtos, uma superfície de API](/index#os-três-produtos-uma-superfície-de-api) para o panorama completo dos três domínios (`api.googa.com.br`, `api.novelai.com.br`, `api.historinhai.com.br`). # Métricas agregadas de engajamento de leitura, por parceiro e período Source: https://developers.googa.com.br/novelai/reference/analytics/métricas-agregadas-de-engajamento-de-leitura-por-parceiro-e-período /novelai/openapi.yaml get /analytics/engagement Suporte aos indicadores prometidos na proposta (DAU/MAU do ritual diário, take-rate, retenção) — sempre agregado ao nível do parceiro, nunca por assinante. Nenhuma resposta desta rota inclui `subscriber_id` em nenhum nível; ver [Privacidade & LGPD](/security/lgpd) para o racional. **Pré-requisito ainda não desenhado em outra página:** para calcular qualquer coisa "por parceiro", as tabelas de leitura (`reading_progress` e afins) precisam de uma coluna `partner_id` — hoje elas não distinguem um leitor que entrou pelo app oficial de um que entrou via SSO de um parceiro. Isso é mencionado como necessidade genérica em [Isolamento multi-tenant](/architecture/supabase-auth-model#capacidades-nativas-do-supabase), mas o backfill/migração real dessa coluna não está feito nem desenhado em detalhe — este endpoint está, portanto, mais atrás no roadmap do que os demais desta especificação, que só precisam do `subscriber_id` já resolvido pela Platform API. `ending_distribution` omite qualquer combinação novela/final com menos de `minimum_cohort_size` leitores no período — supressão de cohort pequeno para reduzir risco de reidentificação, não um limite arbitrário de exibição. # Detalhe de uma novela Source: https://developers.googa.com.br/novelai/reference/catalog/detalhe-de-uma-novela /novelai/openapi.yaml get /novels/{id} # Lista as categorias/gêneros do catálogo Source: https://developers.googa.com.br/novelai/reference/catalog/lista-as-categoriasgêneros-do-catálogo /novelai/openapi.yaml get /categories Utilitário para montar filtros (`category_id` em `GET /novels`) sem depender de uma lista de slugs fixa. Espelha `public.categories`, tabela de leitura pública mesmo no app oficial (não passa por RLS de leitor). # Lista o catálogo de novelas Source: https://developers.googa.com.br/novelai/reference/catalog/lista-o-catálogo-de-novelas /novelai/openapi.yaml get /novels Metadados de catálogo — título, sinopse, categoria, tags editoriais e contagem de capítulos. Não inclui conteúdo de leitura (isso é gated por assinante; ver `GET /novels/{id}/chapters`) nem os finais (`GET /novels/{id}/choices`). Equivalente ao que `public.novels` mais `total_chapters()` expõem hoje ao app oficial. # Lista os capítulos de uma novela e, opcionalmente, o estado de liberação para um assinante Source: https://developers.googa.com.br/novelai/reference/chapters/lista-os-capítulos-de-uma-novela-e-opcionalmente-o-estado-de-liberação-para-um-assinante /novelai/openapi.yaml get /novels/{id}/chapters Sem `subscriber_id`, devolve só o metadado editorial de cada capítulo (número, título, duração estimada) — o equivalente à função interna `list_novel_chapters()`, que não é gated pelo drip porque é metadado, não conteúdo. Com `subscriber_id`, cada capítulo ganha `status` e, quando bloqueado, uma estimativa de `unlocks_at`. **Nota sobre `unlocks_at`:** é um valor calculado pela API a partir de `started_at` do assinante e da regra de drip (1 capítulo/dia, liberação às 06:00 America/Sao_Paulo, 24h antes para plano com early access) — não existe uma coluna com esse valor pronto; o sistema hoje calcula o número de capítulos liberados (`unlocked_chapter_count`) sob demanda a cada leitura, sem persistir "quando o próximo libera". Tratar como estimativa, não como garantia contratual de horário. # Finais disponíveis de uma novela para um assinante Source: https://developers.googa.com.br/novelai/reference/choices/finais-disponíveis-de-uma-novela-para-um-assinante /novelai/openapi.yaml get /novels/{id}/choices Os finais só existem, do ponto de vista de conteúdo, quando o drip libera o último capítulo **para aquele assinante especificamente** — é por isso que `subscriber_id` é obrigatório aqui (diferente de `GET /novels/{id}/chapters`, onde é opcional): não há metadado de finais que possa ser mostrado sem gate, porque o próprio rótulo (`label`) de um final pode ser espoiler. Enquanto o assinante não chegou lá, a resposta é `200` com `available: false` e `choices` vazio — não é um erro, é um estado de negócio normal (a maior parte das chamadas a este endpoint vai cair aqui, para qualquer novela ainda em andamento). # Novelfinished Source: https://developers.googa.com.br/novelai/reference/novelfinished /novelai/openapi.yaml webhook novelFinished Disparado quando um assinante escolhe um final e conclui uma novela (`reading_progress.finished_at` passa de nulo para preenchido) — uma escrita discreta, então mapeia bem no modelo de Database Webhooks nativo do Supabase, descrito em [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model) (seção "Webhooks de saída"). Assinado via HMAC-SHA256, mesmo padrão da Platform API — a verificação passo a passo está em [Eventos (webhooks de saída)](/platform/overview#eventos-webhooks-de-saída). **O que não existe (e por quê):** não há um webhook `chapter.unlocked`. O drip não é uma escrita — `unlocked_chapter_count()` é uma função calculada a cada leitura, sem nenhuma linha que muda no instante em que um capítulo libera às 06:00. Um Database Webhook não tem o que disparar nesse momento. Notificar "seu próximo capítulo chegou" exigiria um job agendado que recalcula o estado de cada assinante ativo e compara contra o que já foi notificado — não está desenhado; fica como questão aberta de roadmap, não como funcionalidade prometida. # Progresso de leitura consolidado de um assinante Source: https://developers.googa.com.br/novelai/reference/progress/progresso-de-leitura-consolidado-de-um-assinante /novelai/openapi.yaml get /subscriber/{id}/reading-progress Uma linha por novela que o assinante já abriu — em andamento ou concluída. Nomeado no singular (`subscriber`, não `subscribers`) para seguir a mesma convenção de `GET /subscriber-status/{id}` na Platform API. `active_novel_count` nunca passa de `active_novel_limit` (hoje fixo em 3): é o limite de novelas simultâneas não finalizadas, aplicado no servidor por `enforce_reading_rules()` — o assinante precisa terminar (ou remover) uma novela em andamento antes de abrir uma quarta. Um parceiro que queira, por exemplo, avisar "sua base já está no limite" numa tela própria tem esse dado aqui sem precisar hardcodar o número 3. # NovelÁudio — visão geral Source: https://developers.googa.com.br/novelaudio/overview Catálogo em áudio, streaming de capítulo e posição de reprodução — e por que isto vive no domínio do NovelAI. Hoje o único cliente do NovelÁudio é o próprio app oficial, falando diretamente com o Supabase do projeto "Novel". Esta página descreve o contrato para uma API de parceiro de áudio. ## Não existe `api.novelaudio.com.br` Este é o ponto que mais gera confusão em quem lê a proposta técnica, então vale ser redundante: **NovelAI e NovelÁudio são atendidos pelo mesmo domínio, `api.novelai.com.br`, porque compartilham o mesmo projeto Supabase** ("Novel") e o mesmo backend físico — Postgres, Auth, Edge Functions e Storage, tudo numa instância só. Não existe um segundo projeto, um segundo domínio ou uma segunda infraestrutura para o NovelÁudio. A aba "NovelÁudio" nesta documentação existe porque os **recursos** são diferentes — catálogo de áudio, streaming de capítulo, posição de reprodução — não porque o domínio é diferente. A rota é que decide se a chamada é sobre texto ou sobre áudio, não o host. Ver [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model) (seção "Custom Domains") para o desenho completo de domínio/projeto, e a tabela de domínios em [/index](/index#os-três-produtos-uma-superfície-de-api). NovelÁudio espelha o grafo de narrativa do NovelAI: a mesma obra, o mesmo motor de fascículos (1 capítulo/dia, VIP com 24h de antecedência) e os mesmos finais — só a camada de áudio é exclusiva deste produto. Não existe um `POST /oauth2/token` próprio do NovelÁudio (nem do NovelAI) — o token é emitido uma única vez pela Platform API, com escopos `novelaudio:*` adicionais na mesma troca. ## O que a API de parceiro expõe `GET /novels/{id}/audio` — por capítulo: título, duração, voz usada (quando já renderizado) e status de renderização. `GET /novels/{id}/chapters/{chapterNumber}/stream` — URL assinada de curta duração para um capítulo liberado, nunca o áudio bruto na resposta. `GET`/`PUT /subscribers/{id}/playback-position` — retomar exatamente de onde parou, entre dispositivos. `GET /voices` — catálogo de vozes de narração para escolha do leitor. **Roadmap de ponta a ponta: não existe catálogo de vozes hoje** — ver a descrição do endpoint. ## Como o áudio é produzido hoje Três caminhos coexistem no código, e só um deles é o que o ouvinte do NovelÁudio de fato usa: 1. **O que o app NovelÁudio realmente toca: áudio pré-gravado.** A narração de cada capítulo é um arquivo gravado uma vez e guardado no bucket **privado** `chapter-audio` do projeto "Novel"; o player pede uma URL assinada de curta duração à Edge Function `audio-url`, que valida o entitlement (plano com áudio + capítulo liberado pelo drip) antes de assinar. Hoje **14 novelas** têm narração real completa (98 arquivos — 7 capítulos cada) — a flag `novels.has_real_audio` controla quais aparecem no catálogo do app. É um arquivo único de bitrate fixo, não streaming adaptativo por segmentos. 2. **A Edge Function de TTS server-side existe no projeto "Novel", mas está desativada na UI.** Havia uma função `tts` (voz padrão única, quota por plano) consumida pelo leitor do app NovelAI para narrar texto sob demanda. Desde 30/jul/2026 essa narração foi ocultada do NovelAI por decisão de produto (`NARRATION_ENABLED = false` em `NovelReader.tsx`) — narração passou a ser exclusividade do NovelÁudio (áudio pré-gravado, caminho 1). A function ainda existe no código, só não é mais chamada por nenhuma tela. 3. **A narração via Web Speech API do navegador é código morto.** O hook existe no repositório do NovelÁudio como resquício de um stand-in antigo, mas nenhuma tela o usa — a reprodução real é o caminho 1. A posição de reprodução entre dispositivos já é real dentro do app oficial: o Supabase sincroniza capítulo atual e posição em segundos por assinante, entre qualquer dispositivo logado. A API de parceiro (`/subscribers/{id}/playback-position`) expõe exatamente esse dado já existente. ## Autenticação Mesmo modelo OAuth2 client credentials usado pela [Platform API](/platform/overview) e descrito em detalhe em [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model) — não repetido aqui. O token é emitido **uma única vez**, de forma centralizada, em `POST https://api.googa.com.br/v1/oauth2/token` (ver [Platform — OAuth2](/platform/reference/oauth2/troca-client-credentials-por-um-token-de-acesso-de-parceiro)) — nunca em `api.novelai.com.br`, que só valida o token recebido via a chave pública do projeto Platform. Um parceiro que integra catálogo de texto e áudio pede os escopos `novelai:*` **e** `novelaudio:*` na mesma troca de credencial, e usa o mesmo token resultante nas chamadas a `api.novelai.com.br` — uma única credencial, uma única troca, independente de quantos domínios de produto o parceiro vai chamar. # Metadados de áudio de uma novela (por capítulo) Source: https://developers.googa.com.br/novelaudio/reference/audio-metadata/metadados-de-áudio-de-uma-novela-por-capítulo /novelaudio/openapi.yaml get /novels/{id}/audio Espelha as tabelas reais `novel_chapters` (metadado do catálogo: título, duração estimada) e `chapter_audio` (metadado do áudio pré-renderizado: voz usada, duração real, status) do mesmo grafo de narrativa do NovelAI — mesma obra, mesmos finais (ver [NovelAI — catálogo](/novelai/reference/catalog/lista-o-catálogo-de-novelas)), agora com uma trilha de áudio por capítulo. Honestidade sobre `audio_status`: hoje **14 novelas** têm narração real gravada (7 capítulos cada = 98 arquivos em `chapter_audio`) no bucket `chapter-audio` — é a flag `novels.has_real_audio` que marca quais são, e é ela que controla o catálogo do app oficial do NovelÁudio (uma 15ª, `t1`, chegou a ser marcada mas foi desmarcada por não ter os arquivos de capítulo gravados — só os finais). Para o resto do catálogo este campo retornaria `not_rendered`. Um pipeline de renderização em lote (TTS → arquivo → upload → linha em `chapter_audio`) é pré-requisito de roadmap para este endpoint valer para o catálogo inteiro. # Atualiza a posição de reprodução do assinante em uma novela Source: https://developers.googa.com.br/novelaudio/reference/playback/atualiza-a-posição-de-reprodução-do-assinante-em-uma-novela /novelaudio/openapi.yaml put /subscribers/{id}/playback-position Upsert por (assinante, novela) — equivalente ao `onConflict: "user_id,novel_id"` já usado pelo app oficial. Chamar de novo com o mesmo `novel_id` substitui a posição anterior; não acumula histórico — por isso repetir a chamada é seguro, sem precisar de header de idempotência (o mecanismo de `Idempotency-Key` chegou a ser proposto, mas não está implementado em nenhuma API Googa). # Consulta a posição de reprodução do assinante em uma novela Source: https://developers.googa.com.br/novelaudio/reference/playback/consulta-a-posição-de-reprodução-do-assinante-em-uma-novela /novelaudio/openapi.yaml get /subscribers/{id}/playback-position **Nota de contrato pendente:** este path usa `subscribers` (plural), enquanto a Platform API usa o singular (`/subscriber-status/{id}`). A escolha do path final é uma decisão em aberto do dono da API antes de qualquer implementação — este endpoint, como o resto deste arquivo, é roadmap. Espelha a tabela real `listening_progress` — uma linha por (usuário, novela): capítulo atual (`chapter_id`, formato do catálogo do player, ex. `t1-ch3`) e posição em segundos dentro dele. É o mesmo mecanismo que já sincroniza "continuar de onde parou" entre dispositivos dentro do próprio app oficial hoje — esta API só expõe essa mesma leitura/ escrita para um sistema de parceiro, em vez do app falar direto com o Supabase. # Emite uma URL de reprodução assinada para um capítulo liberado Source: https://developers.googa.com.br/novelaudio/reference/streaming/emite-uma-url-de-reprodução-assinada-para-um-capítulo-liberado /novelaudio/openapi.yaml get /novels/{id}/chapters/{chapterNumber}/stream Verifica entitlement (plano do assinante inclui áudio + capítulo já liberado pela cadência de 1 capítulo/dia — mesma regra de drip do NovelAI, com acesso antecipado no plano VIP) antes de emitir a URL. Nunca devolve o áudio bruto no corpo da resposta — apenas a URL assinada de curta duração para o player buscar a mídia. Honestidade sobre `format`/adaptação de bitrate: a proposta técnica original promete streaming adaptativo HLS/DASH. O pipeline real hoje (Edge Function `audio-url` sobre o bucket privado `chapter-audio`) assina a URL de um único arquivo mp3/aac de bitrate fixo, com TTL de **1200 segundos (20 minutos)** — o valor no código; foi elevado de 2 minutos porque o player busca a mídia por range requests durante a reprodução e a URL curta expirava no meio de capítulos longos. O valor final ainda depende de uma decisão humana de trade-off segurança × confiabilidade antes do deploy. A URL continua curta demais para virar link de compartilhamento útil, mas isto **não** é streaming adaptativo. Empacotamento HLS/DASH real (segmentação, manifesto, múltiplos bitrates) é trabalho de roadmap ainda não iniciado; até lá, `format` sempre retorna `mp3`. # Lista vozes de narração disponíveis Source: https://developers.googa.com.br/novelaudio/reference/voices/lista-vozes-de-narração-disponíveis /novelaudio/openapi.yaml get /voices **Roadmap de ponta a ponta — não existe catálogo de vozes hoje.** Duas coisas diferentes existem no projeto e nenhuma delas é isto: 1. O app NovelÁudio toca **áudio pré-gravado** (bucket privado `chapter-audio`, servido por URL assinada via a Edge Function `audio-url`) — a voz de cada capítulo é a voz da gravação, não uma escolha do ouvinte. Hoje 14 novelas têm narração real (`novels.has_real_audio`). 2. O app NovelAI (irmão de projeto Supabase, não o NovelÁudio) tem uma Edge Function de TTS que fala com um provedor de terceiro e usa uma voz padrão única, sem opção de escolha pelo leitor — e essa função não é consumida pelo NovelÁudio nem exposta a parceiro nenhum. Nenhum dos dois é "vozes de IA alta fidelidade pt-BR, escolha de narrador pelo leitor" prometido na proposta técnica. Para este endpoint valer, precisa existir: um pipeline de TTS neural server-side com um catálogo real de vozes (nomes, idioma, amostra), desacoplado do provedor específico, e integrado tanto à narração sob demanda quanto à renderização em lote de `chapter_audio`. Nada disso está desenhado em detalhe ainda — este endpoint é um placeholder de contrato, não um desenho fechado como os demais desta especificação. # Platform API — visão geral Source: https://developers.googa.com.br/platform/overview Entitlements, status de assinante, billing e webhooks — a base compartilhada por todo parceiro Googa. A Platform API é a camada comum que todo parceiro integra **uma vez**, independente de quais produtos (NovelAI, HistorinhAI, NovelÁudio) ele vai ativar. Ela resolve quatro problemas: **Entitlements** — ativa, suspende ou cancela o acesso de um assinante a um produto, no momento em que o status dele muda no sistema do parceiro (nova assinatura, upgrade, suspensão por inadimplência). **Subscriber Status** — consulta pontual do que um assinante tem direito a acessar em um produto, independente de quando o entitlement foi emitido. **Billing Usage** — a contagem de exemplares ativos, base para a reconciliação da Nota de Débito mensal. **SSO / OIDC** — *planejado, ainda não implementado*: login federado, em que o assinante entra pelo app do parceiro (ex: Minha Algar) e cai autenticado no produto Googa, sem criar senha nova. ## Autenticação Toda chamada de servidor-a-servidor (Entitlements, Subscriber Status, Billing Usage) usa OAuth2 **client credentials** — seu backend troca `client_id`/`client_secret` por um token de curta duração (10 minutos) em `POST /oauth2/token`, e usa esse token nas chamadas seguintes. As credenciais são aceitas via **HTTP Basic** (`Authorization: Basic base64(client_id:client_secret)`, RFC 6749 §2.3.1 — a forma preferida) ou nos campos do corpo `application/x-www-form-urlencoded`. Cada endpoint exige um escopo específico (`entitlements:write`, `subscriber:read`, `billing:read`); os escopos do token são os cadastrados na credencial do parceiro. Ver [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model) para o desenho interno completo. O SSO do assinante (`GET /oauth2/authorize`) é um fluxo diferente — de navegador, não de API — e está **planejado, ainda não implementado**: não existe hoje endpoint de SSO em nenhum ambiente. ## Domínio ``` https://api.googa.com.br/v1 ``` Este é o único domínio da Platform API — ele é o mesmo independente de quais produtos o parceiro ativa. As APIs específicas de cada produto (catálogo, progresso de leitura, streaming de áudio) vivem em domínios próprios: `api.novelai.com.br` (NovelAI **e** NovelÁudio, que compartilham o mesmo backend) e `api.historinhai.com.br`. Ver as abas correspondentes. ## Eventos (webhooks de saída) | Evento | Quando dispara | | ----------------------- | ----------------------------------------------------------------- | | `subscriber.updated` | Entitlement de um assinante é criado ou atualizado (status/plano) | | `subscription.canceled` | Status do entitlement transiciona para `canceled` | O mecanismo real: um Database Webhook nativo do Supabase (trigger `pg_net`) dispara, na mudança de linha, uma chamada à função de despacho (`webhook-dispatch`, projeto Platform), que **assina o payload com HMAC-SHA256** e entrega ao `webhook_url` cadastrado do parceiro. A entrega ao parceiro é feita em **uma única tentativa por disparo** — o retry nativo do Database Webhook cobre falha ao invocar a função de despacho, mas não existe fila própria de reentrega ao endpoint do parceiro. Responda 2xx rápido. **Verificando a assinatura** (o essencial): 1. Leia o **corpo bruto** da requisição (bytes, antes de qualquer parse de JSON). 2. Calcule HMAC-SHA256 do corpo usando o `webhook_secret` combinado no cadastro do parceiro. 3. Compare o resultado (hex), em tempo constante, com o header `X-Googa-Signature` (formato `sha256=`). 4. O header `X-Googa-Event` traz o nome do evento (`subscriber.updated` / `subscription.canceled`) sem precisar parsear o corpo. O payload tem o formato `{ "event": "...", "occurred_at": "...", "data": { "subscriber_id", "product", "status" } }` — ver os schemas na Referência de API. # Consulta o consumo do período para reconciliação de billing Source: https://developers.googa.com.br/platform/reference/billing/consulta-o-consumo-do-período-para-reconciliação-de-billing /platform/openapi.yaml get /billing-usage Contagem de exemplares ativos do parceiro no produto, base para a Nota de Débito mensal. **Simplificação conhecida (v1):** ainda não há histórico por período — a contagem reflete o estado **atual** de entitlements ativos, independente do `period` pedido (o campo `note` da resposta repete esse aviso). Uso real de billing por período exige uma tabela de snapshot/evento, planejada para quando houver parceiro reconciliando Nota de Débito mensal em produção. # Ativa, suspende ou cancela o acesso de um assinante a um produto Source: https://developers.googa.com.br/platform/reference/entitlements/ativa-suspende-ou-cancela-o-acesso-de-um-assinante-a-um-produto /platform/openapi.yaml post /entitlements Upsert por (parceiro, assinante, produto): chamar novamente com o mesmo assinante/produto e um status diferente atualiza o entitlement existente — não cria duplicado. Por ser um upsert, repetir a mesma chamada é seguro; não há (nem é necessário) um header `Idempotency-Key` — esse mecanismo chegou a ser proposto, mas não está implementado. Enquanto o SSO não existe, o entitlement fica registrado em uma tabela própria de parceiro no projeto do produto (`partner_subscribers`) — ele **não** cria nem altera a assinatura de nenhuma conta do app oficial. Ver [Modelo de dados](/architecture/data-model). # Chave pública (JWKS) do emissor de tokens de parceiro Source: https://developers.googa.com.br/platform/reference/keys/chave-pública-jwks-do-emissor-de-tokens-de-parceiro /platform/openapi.yaml get /jwks Endpoint público (sem autenticação) com a chave pública ES256 usada para verificar a assinatura do JWT de serviço emitido por `POST /oauth2/token`. É assim que os projetos de produto (Novel, HistorinhAI) validam o token do parceiro sem depender de segredo compartilhado. Respondido com `Cache-Control: public, max-age=300`. # Início do login federado do assinante (SSO OIDC) — planejado Source: https://developers.googa.com.br/platform/reference/oauth2/início-do-login-federado-do-assinante-sso-oidc-—-planejado /platform/openapi.yaml get /oauth2/authorize **Planejado — ainda não implementado.** Não existe hoje nenhum endpoint de SSO em nenhum ambiente, e nenhum IdP de parceiro está configurado. Esta operação documenta o contrato de destino, não algo disponível para chamada. Quando existir: endpoint de **redirecionamento de navegador**, não uma chamada JSON — o app do parceiro (ex: Minha Algar) redireciona o navegador/webview do assinante para aqui. O Supabase Auth de cada produto atua como *Relying Party* do provedor OIDC do parceiro: valida o `id_token` recebido, cria/recupera o usuário e devolve uma sessão de app normal. Ver o desenho em [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model). # Troca client credentials por um token de acesso de parceiro Source: https://developers.googa.com.br/platform/reference/oauth2/troca-client-credentials-por-um-token-de-acesso-de-parceiro /platform/openapi.yaml post /oauth2/token Implementa o grant `client_credentials` do OAuth 2.0 (RFC 6749 §4.4). O token retornado autentica chamadas de servidor-a-servidor (Entitlements, Subscriber, Billing) — não é um token de usuário final. TTL curto (10 minutos); o cliente deve renovar antes de expirar, não reutilizar tokens vencidos. **Autenticação do cliente:** as credenciais são aceitas via HTTP Basic (`Authorization: Basic base64(client_id:client_secret)`, RFC 6749 §2.3.1 — **forma preferida**) ou nos campos `client_id`/`client_secret` do corpo (`client_secret_post`). O corpo é sempre `application/x-www-form-urlencoded`. **Escopos:** os escopos do token são os cadastrados na credencial do parceiro — não há parâmetro `scope` na requisição; pedir um subconjunto de escopos por chamada não é suportado hoje. # Consulta o status de um assinante em um produto Source: https://developers.googa.com.br/platform/reference/subscriber/consulta-o-status-de-um-assinante-em-um-produto /platform/openapi.yaml get /subscriber-status/{id} Consulta pontual do entitlement de um assinante para **um produto por chamada** — o parâmetro `product` é obrigatório. Agregar todos os produtos numa única resposta fica para uma versão futura, quando um segundo parceiro/produto justificar o fan-out. Um assinante que nunca teve entitlement emitido por este parceiro não é um erro: a resposta é `200` com `status: "none"`. # Subscriberupdated Source: https://developers.googa.com.br/platform/reference/subscriberupdated /platform/openapi.yaml webhook subscriberUpdated Disparado quando o entitlement de um assinante muda do lado da Googa (criação ou atualização de status/plano). Assinado via HMAC-SHA256 do corpo bruto, entregue com os headers `X-Googa-Signature: sha256=` e `X-Googa-Event: subscriber.updated` — ver a verificação passo a passo em [Eventos (webhooks de saída)](/platform/overview#eventos-webhooks-de-saída). **Entrega:** uma única tentativa por disparo — não há fila própria de reentrega ao endpoint do parceiro. Responda 2xx rápido; qualquer não-2xx é registrado, mas não gera retry dedicado do lado da Googa. # Subscriptioncanceled Source: https://developers.googa.com.br/platform/reference/subscriptioncanceled /platform/openapi.yaml webhook subscriptionCanceled Disparado quando o status do entitlement transiciona para `canceled`. Mesmo formato de payload e de assinatura do `subscriber.updated` (headers `X-Googa-Signature` e `X-Googa-Event: subscription.canceled`); o payload não inclui campo de motivo do cancelamento — o parceiro é a fonte desse status, então ele já conhece o motivo do próprio lado. # Política de Uso da API Source: https://developers.googa.com.br/security/api-usage-policy Termos que regem o uso das credenciais e dos endpoints da API de parceiro Googa — elegibilidade, uso aceitável, segurança de credenciais, limites, IP e rescisão. **Rascunho técnico — pendente de revisão jurídica formal.** Este documento foi redigido pela equipe técnica da Googa como base real para a Política de Uso da API, no formato e com o nível de detalhe de um Terms of API Use de mercado. Ele **não é** um instrumento jurídico já validado por advogado nem foi assinado como parte de nenhum contrato — está publicado aqui para fins de avaliação técnica no âmbito do RFP Livros Digitais 2026 (Algar Telecom) e para servir de insumo à revisão jurídica que precisa correr antes de se tornar vinculante. Onde houver conflito entre este documento e o contrato comercial assinado entre a Googa e um parceiro, o contrato prevalece. Esta política descreve as regras de uso das APIs Googa (Platform, NovelAI, HistorinhAI e NovelÁudio, ver [Platform API — visão geral](/platform/overview)) por parceiros integradores. ## 1. Objeto e aceite Esta Política de Uso da API ("Política") rege o acesso e o uso das APIs, SDKs, sandbox e documentação técnica da Googa (coletivamente, a "API") por parceiros integradores ("Parceiro", "você"). Ela é complementar ao contrato comercial firmado entre a Googa e o Parceiro (o "Contrato de Parceria") — não o substitui, e não cria por si só nenhum direito de acesso à API na ausência de um Contrato de Parceria vigente. A obtenção, ativação ou uso de qualquer credencial de API (`client_id`/`client_secret`, API key ou token emitido a partir delas) constitui aceite integral desta Política pelo Parceiro e vincula todos os sistemas, prestadores de serviço e pessoas que atuem em seu nome. Se você não concorda com algum termo, não deve ativar ou usar as credenciais. ## 2. Elegibilidade e cadastro A API Googa **não é uma API pública de autoatendimento**. Diferente de uma API de consumidor onde qualquer desenvolvedor cria uma conta e começa a chamar endpoints, o acesso aqui é B2B enterprise e pressupõe, nesta ordem: 1. Um Contrato de Parceria assinado entre a pessoa jurídica do Parceiro e a Googa, definindo produtos contratados (NovelAI, HistorinhAI, NovelÁudio), volume, condições comerciais e SLA. 2. Um termo de integração técnica, formalizando os ambientes (sandbox e produção), os escopos de API autorizados e os responsáveis técnicos de cada lado. 3. Emissão de credenciais pela Googa — nunca por autocadastro. Não emitimos credenciais para pessoa física, para pessoa jurídica sem Contrato de Parceria vigente, ou para qualquer uso que não esteja coberto pelo escopo contratado. Credenciais de sandbox podem ser emitidas antes da assinatura final, exclusivamente para fins de avaliação técnica (ex.: piloto de RFP), e não autorizam tráfego de dados reais de assinante nem uso em produção. ## 3. Uso aceitável ### Uso permitido A API deve ser usada exclusivamente para integrar, dentro do escopo contratado, as funções de entitlement, billing, SSO e catálogo necessárias para que o Parceiro ofereça os produtos Googa contratados aos próprios assinantes — por exemplo, ativar/consultar entitlements, reportar uso para reconciliação de billing, autenticar o assinante via SSO, ou exibir catálogo e progresso de leitura/escuta na superfície do próprio Parceiro. ### Uso proibido É expressamente proibido: * **Scraping ou extração em massa do catálogo** para qualquer finalidade fora do escopo contratado, incluindo reconstrução do catálogo em outro sistema, indexação para terceiros ou reuso após o término do Contrato de Parceria. * **Acessar ou tentar acessar dados de assinantes fora da própria base do Parceiro** — cada Parceiro só pode consultar, ativar ou receber eventos referentes aos assinantes que ele próprio provisionou via `subscriber_id`. Qualquer tentativa de enumeração, força bruta de identificadores ou acesso cruzado à base de outro parceiro é violação grave desta Política. * **Engenharia reversa do conteúdo ou das obras para fins de republicação** — as obras entregues via API (texto, áudio, metadados editoriais, incluindo dados de ISBN) são ativos protegidos por direito autoral da Googa e de seus autores/editoras parceiras — cada obra é registrada com ISBN na Biblioteca Nacional, como e-book ou audiolivro (ver [Propriedade intelectual](#7-propriedade-intelectual)). Extrair, decompilar ou reconstruir o conteúdo para redistribuição, treinamento de modelo de terceiro ou publicação fora do produto Googa contratado é proibido. * **Qualquer tentativa de re-identificar ou perfilar menores a partir de dados agregados do HistorinhAI.** A API de parceiro nunca expõe dado identificável de criança (ver [Política de Privacidade da API](/security/privacy-policy) e [Proteção de dados de menores — ECA](/security/child-data-eca)); é proibido combinar dados agregados, de billing ou de qualquer outra origem na tentativa de inferir a identidade, o perfil comportamental ou os hábitos de uma criança específica. * **Automação ou volume de chamadas incompatível com o uso justo** descrito em [Rate limits e uso justo](#5-rate-limits-e-uso-justo) — incluindo contornar qualquer limitação de tráfego com múltiplas credenciais, IPs rotativos ou qualquer técnica de evasão. * **Revenda, sublicenciamento ou disponibilização do acesso à API para terceiros** sem autorização prévia e expressa por escrito da Googa — as credenciais são emitidas para o Parceiro identificado no Contrato de Parceria, não para uso por clientes, fornecedores ou parceiros do Parceiro. ## 4. Credenciais e segurança O Parceiro é responsável por proteger `client_secret`, API keys e qualquer token derivado deles com o mesmo padrão de cuidado que aplicaria a uma credencial de produção crítica própria — armazenamento em cofre de segredos, nunca em código-fonte versionado, nunca em log de aplicação. * **Rotação obrigatória** em caso de suspeita de comprometimento (exposição acidental, ex- funcionário com acesso, log vazado, etc.), a ser solicitada imediatamente pelo canal de suporte (ver [Contato](#10-contato)). A Googa pode revogar unilateralmente uma credencial que apresente padrão de uso compatível com comprometimento, notificando o Parceiro assim que possível. * **Responsabilidade pelo uso.** O Parceiro é integralmente responsável por toda chamada feita com suas credenciais, inclusive as feitas por sistemas terceirizados que operem em seu nome (ex.: integrador contratado pelo Parceiro) — a Googa não distingue, para fins de auditoria e responsabilização, entre uma chamada feita pelo time do Parceiro e uma chamada feita por terceiro autorizado por ele. Detalhes técnicos do modelo de emissão e verificação de credenciais estão em [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model). ## 5. Rate limits e uso justo **Não há hoje limites numéricos de requisição publicados** — eles serão definidos e documentados antes da disponibilidade geral da API, e existirão para proteger a disponibilidade da plataforma para todos os parceiros, não como limite comercial de volume de assinantes. Um ambiente de sandbox separado da produção também ainda não existe (é planejado); até lá, não há distinção de limites por ambiente. Até a publicação dos limites, vale o princípio de **uso justo**: o volume de chamadas deve ser compatível com a base de assinantes do Parceiro e com os fluxos de integração documentados. Em caso de uso abusivo recorrente — chamadas muito acima do padrão esperado para o volume de assinantes do Parceiro, ou tentativas de evasão de limitações de tráfego — a Googa pode aplicar, em ordem de severidade: aviso prévio ao responsável técnico do Parceiro quando o padrão permitir identificação sem risco à plataforma; throttling adicional temporário; e suspensão de credenciais, com aviso prévio sempre que a natureza do abuso não exigir ação imediata para conter risco à segurança ou à disponibilidade da plataforma para outros parceiros. ## 6. Disponibilidade e SLA O compromisso de disponibilidade (99% de uptime mensal, suporte dedicado 24×7 com P1 em 15 minutos, créditos de serviço por descumprimento) está descrito no SLA comercial acordado com cada Parceiro. Este SLA **vale exclusivamente para o ambiente de produção** — o ambiente de sandbox é fornecido "como está", sem compromisso de disponibilidade, e não deve ser usado para nenhum fluxo que dependa de disponibilidade garantida. ## 7. Propriedade intelectual A Googa mantém, em caráter exclusivo, todos os direitos de propriedade intelectual sobre o conteúdo entregue via API — incluindo texto, áudio, metadados editoriais, capas e qualquer obra registrada com ISBN na Biblioteca Nacional, seja de autoria própria ou sob contrato com autores e editoras parceiras. O uso da API concede ao Parceiro uma licença limitada, não exclusiva, não transferível e revogável, para exibir o conteúdo efetivamente contratado aos próprios assinantes finais, dentro do escopo, do território e do prazo definidos no Contrato de Parceria. Nada nesta Política ou no uso da API transfere qualquer direito de propriedade, de reprodução fora do produto contratado, de distribuição a terceiros, ou de uso do conteúdo após o término do vínculo com o assinante ou do próprio Contrato de Parceria. ## 8. Suspensão e rescisão A Googa pode suspender ou revogar credenciais de API, total ou parcialmente, nas seguintes hipóteses: * Violação de qualquer termo desta Política, em especial das restrições da seção [Uso aceitável](#3-uso-aceitável); * Inadimplência do Contrato de Parceria comercial subjacente; * Uso que coloque em risco a segurança, a integridade ou a disponibilidade da plataforma Googa ou de dados de terceiros (incluindo outros parceiros e seus assinantes). Sempre que a natureza da violação permitir sem agravar o risco, a Googa notifica o Parceiro e concede prazo razoável para regularização antes da suspensão. Em caso de risco iminente à segurança da plataforma ou de dados de terceiros, a suspensão pode ser imediata, com comunicação posterior. Após a rescisão do Contrato de Parceria — por qualquer motivo — as credenciais são revogadas e o acesso à API é encerrado. O tratamento dos dados de integração já registrados (logs de chamadas, eventos de webhook) segue o prazo de retenção definido na [Política de Privacidade da API](/security/privacy-policy#5-retenção-dos-dados-de-integração); dados de billing necessários para reconciliação de valores já devidos são preservados pelo prazo legal aplicável, independentemente da rescisão. ## 9. Alterações a esta política Esta Política pode ser atualizada para refletir evolução técnica da API, mudanças regulatórias ou ajustes de escopo. Alterações são comunicadas por changelog público e, quando aplicável, aviso direto ao responsável técnico de cada Parceiro. Alterações materiais (que restrinjam uso hoje permitido, alterem limites de forma relevante, ou mudem a alocação de responsabilidade entre as partes) têm aviso prévio mínimo de **30 dias** antes de entrarem em vigor, exceto quando a mudança for exigida por lei, ordem judicial, ou por necessidade imediata de mitigar risco de segurança — casos em que a Googa comunica a alteração assim que possível, ainda que já vigente. ## 10. Contato Dúvidas sobre esta Política, solicitação de rotação de credenciais ou reporte de uso suspeito: [developers@googa.com.br](mailto:developers@googa.com.br). # Proteção de dados de crianças — LGPD Art. 14 & ECA Source: https://developers.googa.com.br/security/child-data-eca Consentimento parental, proibição de perfilamento comercial, retenção reforçada e o direito dos pais de excluir os dados do filho — o tratamento específico do HistorinhAI. Esta página cobre exclusivamente o **HistorinhAI**. Para a restrição de dado do lado da API de parceiro (o que a Algar recebe e, mais importante, o que ela **nunca** recebe), ver [HistorinhAI — visão geral](/historinhai/overview). ## Por que este produto tem uma página própria O HistorinhAI trata dado de criança e adolescente. Duas normas se somam aqui, não uma substitui a outra: * **LGPD, Art. 14** — regras específicas para tratamento de dados de crianças e adolescentes, incluindo o requisito de consentimento parental em destaque. * **ECA (Estatuto da Criança e do Adolescente, Lei 8.069/1990)** — o arcabouço de proteção integral que informa o *padrão* de cuidado esperado, mesmo onde não fala de dado pessoal diretamente (a LGPD trata do dado; o ECA trata da criança). Isso já é a razão por trás de uma decisão de arquitetura citada em outras páginas: o HistorinhAI roda em um projeto Supabase isolado dos demais produtos (ver [Modelo de autenticação](/architecture/supabase-auth-model) e [Mapeamento de dados](/security/data-processing)) — não é só organização de código, é isolamento de um tipo de dado que exige tratamento diferente do resto da plataforma. ## Consentimento parental (Art. 14, §1º) O Art. 14, §1º da LGPD exige consentimento **específico e em destaque**, dado por pelo menos um dos pais ou pelo responsável legal, para o tratamento de dados de criança. Sendo honestos sobre o estado atual: o fluxo de cadastro do HistorinhAI hoje **gate-keeps corretamente por adulto** (só quem cria a conta com e-mail e senha pode adicionar um perfil de criança — não existe caminho para uma criança se cadastrar diretamente), mas a tela de criação de conta (`AccountStep`) **não apresenta hoje um texto de consentimento específico e em destaque** nos termos literais do Art. 14, §1º — é uma tela de e-mail/senha sem uma declaração explícita do tipo "sou responsável legal e autorizo o tratamento dos dados da criança conforme a Política de Privacidade". Isso é um gap real que identificamos ao revisar o componente, não um detalhe formal: registramos aqui como item de correção prioritário, e não vamos descrever uma tela que ainda não existe como se já estivesse em produção. O que **já** é real hoje, e vale como parte da mitigação: * A ordem do onboarding é: 1) nome do responsável → 2) criação de conta (e-mail/senha, adulto) → 3\) plano → e só então (dentro do app, já autenticado) o cadastro do perfil da criança. Uma criança não consegue, por si só, chegar ao ponto de fornecer dado próprio sem que um adulto já tenha criado e autenticado a conta. * O modelo de família (`families`/`family_members`) trata a conta como pertencendo a adultos — perfis de criança (`children`) são sempre subordinados a uma família com pelo menos um adulto responsável (`owner_user_id`), nunca uma entidade que se autogerencia. **Correção proposta (Roadmap imediato, não um item distante)**: adicionar, na etapa de criação de conta, um texto de consentimento específico e em destaque (não apenas um link genérico de "termos de uso" no rodapé) nomeando explicitamente o tratamento de dado da criança, com checkbox próprio e obrigatório antes de liberar o cadastro do primeiro perfil de criança. Isso é o desenho correto segundo a lei — sinalizamos a ausência em vez de descrevê-lo como já resolvido. ### Melhor interesse da criança (Art. 14, §2º) — por que não se aplica como excludente aqui O Art. 14, §2º permite, excepcionalmente, coletar dado de criança **sem** consentimento específico quando estritamente necessário para proteção da criança (ex: prevenção a dano, situações de segurança). Esse não é o fundamento usado pelo HistorinhAI — o produto coleta dado para fins de personalização de conteúdo educativo/lúdico e relatório aos pais, que é uma finalidade comercial legítima, mas não uma finalidade de proteção que dispensaria consentimento. Por isso o consentimento específico do §1º é a base correta a operacionalizar — a exceção do §2º não se aplica e não deve ser usada como atalho. ## Proibição de perfilamento comercial de menores Nenhum dado de criança alimenta segmentação de anúncio, é vendido, ou é compartilhado com terceiros para fins comerciais — isso inclui explicitamente o parceiro de distribuição (ex: Algar): * A **API de parceiro** só expõe entitlement (o assinante tem acesso ao produto, sim/não) e billing agregado (quantos exemplares ativos, para reconciliação de cobrança) — nunca perfil de criança, nunca histórico de leitura individual, nunca as competências mapeadas no relatório mensal. O detalhamento de exatamente quais campos a API expõe (e a garantia estrutural — não apenas de política — de que dado de criança nunca aparece nesses endpoints) está em [HistorinhAI — visão geral](/historinhai/overview). * Internamente, a personalização (seleção de história por perfil/objetivo) usa o dado da própria criança para servir **aquela mesma criança** — não para treinar segmentação vendável a terceiros, nem para segmentar publicidade dentro ou fora do produto. O HistorinhAI não veicula publicidade de terceiros. * A síntese de voz (TTS) do HistorinhAI passa por um provedor externo (ver [Mapeamento de dados](/security/data-processing)) apenas para converter texto em áudio — a chamada é autenticada e sujeita a quota (`consume_tts_quota`), e o texto enviado é o conteúdo da história, não um perfil da criança. ## Retenção mais curta e específica Estes prazos são a proposta da Googa para dado de criança — mais curtos que o prazo geral descrito em [LGPD — Retenção](/security/lgpd#retenção), refletindo o cuidado adicional exigido pelo Art. 14 e pelo ECA. | Categoria | Prazo proposto | | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Histórias lidas / sessões de leitura da criança (telemetria granular) | 6 meses, depois agregado só ao nível de competência (ex: "Vocabulário +6") sem o texto/evento original | | Relatório mensal enviado aos pais | Mantido enquanto a conta estiver ativa; removido junto com a exclusão do perfil da criança | | Perfil da criança (idade, interesses, desafio do mês) | Enquanto o perfil existir — excluído imediatamente quando os pais removem o perfil ou a conta (ver abaixo), sem período de retenção "por segurança" adicional | Diferente do dado financeiro de um adulto (que pode ter prazo de guarda fiscal obrigatório — ver [LGPD](/security/lgpd#retenção)), não há justificativa legal para reter dado de criança além do necessário à própria prestação do serviço — por isso o prazo é deliberadamente mais curto e sem excepcionalidade fiscal. ## Direito dos pais de excluir os dados do filho a qualquer momento Isso já está implementado, não é uma promessa: o perfil de uma criança (`children`) é removível diretamente pelo responsável dentro do app, e a policy `children_delete_family` garante que só um membro da própria família pode fazer isso — sem depender de suporte manual. Ao excluir a **conta** inteira (não só um perfil de criança), a função `delete_my_account()` do HistorinhAI apaga `reading_sessions`, `subscriptions` e `children` da família antes de remover a família e a conta do responsável — descrito em detalhe técnico em [Mapeamento de dados — propagação de exclusão](/security/data-processing#como-um-pedido-de-exclusão-se-propaga). Não existe hoje uma cópia de backup ou log separado que sobrevive a esse fluxo com o perfil da criança identificável. ## Resumo do que é GA vs. Roadmap nesta página | Item | Status | | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | Adulto obrigatório antes de qualquer dado de criança (gate estrutural) | **GA** | | Isolamento do dado de criança em projeto Supabase próprio | **GA** | | Exclusão de perfil/conta de criança sob controle dos pais, a qualquer momento | **GA** | | Nenhum dado de criança exposto à API de parceiro (estrutural, não só política) | GA no desenho da Platform API — ver [HistorinhAI — visão geral](/historinhai/overview) | | Texto de consentimento específico e em destaque (Art. 14, §1º) na tela de cadastro | **Roadmap — gap identificado, correção prioritária** | | Retenção mais curta automatizada (agregação após 6 meses) | Roadmap — hoje a retenção não é purgada automaticamente, só por exclusão explícita | | RIPD formal documentando este tratamento | Roadmap — ver [LGPD — RIPD](/security/lgpd#ripd-relatório-de-impacto-à-proteção-de-dados) | # Mapeamento de fluxo de dados Source: https://developers.googa.com.br/security/data-processing Onde cada dado entra, em qual projeto Supabase é processado e armazenado, quem tem acesso interno, e como um pedido de exclusão se propaga pelas tabelas. Esta página é o complemento operacional de [LGPD](/security/lgpd) — aqui o foco é o caminho técnico real do dado, não o enquadramento legal. ## Entrada — de onde o dado vem | Origem | Como chega | Status | | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | | App oficial (Web/PWA — não há apps nativos) | Direto para o Supabase do produto via SDK cliente (`@supabase/supabase-js`), autenticado com JWT de usuário | **GA** | | Webhook **de entrada** do parceiro (ex: Algar chamando um endpoint de webhook da Googa) | Não existe e não está desenhado — a mudança de plano entra pela API (`POST /entitlements`), não por webhook de entrada | — | | Webhook **de saída** (Googa → parceiro: `subscriber.updated`, `subscription.canceled`) | Implementado no código (função `webhook-dispatch`, assinatura HMAC, entrega única — ver [Modelo de autenticação](/architecture/supabase-auth-model)); deploy em produção pendente | Código pronto, deploy pendente | | Edge Function de terceiro (TTS, e-mail) | O app chama a Edge Function do próprio produto, que por sua vez chama o provedor externo (gateway de LLM/TTS) — o dado do usuário (texto a sintetizar) trafega por esse provedor, mas a orquestração e a quota são controladas pela Googa | **GA** | ## Onde é processado e armazenado | Produto | Projeto Supabase | Isolamento | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | NovelAI + NovelÁudio | "Novel" (``) | Compartilhado entre os dois produtos — mesmo Postgres, RLS separa por `user_id`/`app` | | HistorinhAI | "HistorinhAI" (``) | Projeto próprio, isolado dos demais — decisão deliberada dado o tratamento de dados de crianças | | Platform (API de parceiro) | Projeto dedicado — já existe no código (schema e Edge Functions no repo `googa-platform`), deploy em produção pendente | Guarda só metadado de integração, nunca dado de leitor: `partners` (incluindo `webhook_url` e `webhook_secret` — este em texto puro **de propósito**, porque assinar HMAC de cada entrega exige o segredo de volta; a tabela é acessível só por `service_role`), `partner_credentials` (hash do secret) e `partner_api_keys` — ver [Modelo de autenticação](/architecture/supabase-auth-model) | Cada projeto é Postgres com Row Level Security habilitado nas tabelas que guardam dado de usuário — não existe uma cópia "de leitura geral" fora do RLS para uso interno (ex: um data warehouse espelhado sem controle de acesso próprio). Duas funções ilustram os dois padrões usados: `export_my_data()` é `security invoker` DE PROPÓSITO — roda com o privilégio de quem chama, então cada subconsulta interna ainda passa pelo RLS de cada tabela (dupla trava). Já `delete_my_account()` precisa de `security definer` pra de fato contornar o RLS (apagar linhas em cascata que o próprio chamador não teria permissão de apagar direto) — e por isso é escrita para filtrar explicitamente pelo próprio `auth.uid()`/`family_id` do chamador, nunca por um parâmetro livre. ## Quem tem acesso interno Hoje o controle de acesso interno é o modelo de membros de projeto do próprio Supabase (quem tem login no dashboard do projeto) — não existe ainda uma segmentação formal de papéis internos (editorial, engenharia, suporte) com permissões diferenciadas por função dentro da plataforma: | Papel interno (proposto) | Acesso pretendido | Status | | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | Engenharia | Acesso completo ao projeto Supabase (schema, funções, dados) para debug e operação | **GA hoje** (mas sem segmentação — é "acesso total" para quem está no time, não escopado por tarefa) | | Editorial (curadoria de catálogo) | Acesso só às tabelas de catálogo/conteúdo (obras, capítulos, metadados), sem acesso a dado de usuário/família | Roadmap — hoje quem cura catálogo não tem uma visão de banco separada de quem opera o backend | | Suporte ao cliente | Acesso de leitura a conta/assinatura de um usuário específico mediante ticket, sem acesso a dado de outros usuários nem a exportação em massa | Roadmap — hoje suporte é feito manualmente por quem já tem acesso de engenharia | Essa segmentação formal (RBAC interno por função, não só por produto) é um item real de roadmap de maturidade organizacional — citamos aqui sem inflar: hoje o time é pequeno o suficiente para que o acesso "de fato" seja mais amplo do que o princípio de menor privilégio recomendaria em regime permanente, e achamos mais honesto declarar isso do que descrever uma segmentação que ainda não existe. ## Como um pedido de exclusão se propaga A exclusão de conta usa duas camadas: `on delete cascade` no schema (para o caso simples) e uma função explícita para os casos onde apagar em cascata ingenuamente afetaria outra pessoa. **Caso simples — NovelAI/NovelÁudio** (conta individual, sem conceito de família): a função `delete_my_account()` apaga a linha em `auth.users`, e isso cascateia automaticamente para `profiles`, `subscriptions`, `favorites`, `reading_progress`, `listening_progress`, `tts_usage`, `audio_access_log`, `email_log`, `free_time_grants` e `referral_codes` — todas com `on delete cascade` apontando para `auth.users(id)`. Uma tabela exigiu ajuste antes: `promo_codes` tinha `created_by` sem regra de exclusão (`NO ACTION`), o que impediria um administrador de excluir a própria conta sem quebrar os códigos promocionais que ele criou — trocado para `on delete set null`, preservando o código para quem já o resgatou. **Caso com família — HistorinhAI**: apagar em cascata direto pela conta seria perigoso, porque uma família pode ter mais de um adulto (`family_members`). A função `delete_my_account()` primeiro verifica se a pessoa é **dona** de uma família com outros membros — se sim, bloqueia com `family_has_other_members` até que os outros membros sejam removidos primeiro (fluxo já disponível no app). Registros que a pessoa criou mas que pertencem a uma família da qual ela é só membro (`children.user_id`, `reading_sessions.user_id` como proveniência, não como posse) são reatribuídos ao dono da família antes da exclusão, para não apagar dado de uma família que ela só visitava. Só quando a pessoa é dona sem outros membros é que a função apaga explicitamente `reading_sessions`, `subscriptions` e `children` da própria família antes de apagar a família e, por fim, a linha em `auth.users` — que cascateia o resto (perfil, código de indicação, etc.). Este desenho — cascade automático onde é seguro, função explícita onde exige avaliar posse compartilhada primeiro — é o que garante que um pedido de exclusão (Art. 18, VI da LGPD) nunca deixa dado pessoal órfão nem, no outro extremo, remove acesso de alguém que não pediu para saber saída da família. # Resposta a incidentes Source: https://developers.googa.com.br/security/incident-response Classificação de severidade, tempos de resposta e o fluxo de comunicação — incluindo quando um incidente com dados pessoais aciona a ANPD. **Status: processo proposto.** Isto operacionaliza o compromisso de SLA assumido na proposta técnica GoogaBooks (suporte dedicado 24×7, P1 em 15 minutos) — não descreve uma central de operações de segurança já rodando com essa maturidade. Ver [Segurança — visão geral](/security/overview) para o que já está em produção hoje. ## Classificação de severidade | Severidade | Definição objetiva | Exemplos | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | **P1 — Crítico** | Indisponibilidade total do serviço para todos os usuários/parceiros, **ou** exposição/vazamento confirmado de dados pessoais, **ou** comprometimento de credencial com privilégio elevado (chave de serviço, credencial de parceiro). | API de parceiro fora do ar; RLS bypassed confirmado; dado de criança exposto a terceiro não autorizado. | | **P2 — Alto** | Degradação severa afetando um produto inteiro ou uma função crítica (ex: pagamento, login), sem confirmação de exposição de dados pessoais. Inclui vulnerabilidade de segurança exploitável reportada, ainda sem evidência de exploração. | TTS fora do ar para todo o HistorinhAI; falha de autenticação impedindo login de todos os usuários de um produto. | | **P3 — Médio** | Degradação parcial ou intermitente; bug funcional sem exposição de dados nem impacto de segurança; indisponibilidade de uma feature não crítica. | Relatório mensal não é gerado para uma parcela de famílias; geração de capítulo lenta. | | **P4 — Baixo** | Impacto cosmético ou de baixo risco, sem impacto funcional relevante nem de segurança. | Texto incorreto na UI; log verboso demais. | ## Tempo de resposta por severidade | Severidade | Resposta inicial | Atualizações | | ---------- | ------------------------------------------------------ | --------------------------- | | P1 | 15 minutos (compromisso de SLA da proposta GoogaBooks) | A cada 30 min até contenção | | P2 | 1 hora em horário comercial estendido | A cada 2h até mitigação | | P3 | 1 dia útil | No fechamento | | P4 | Próximo ciclo de planejamento | — | "Resposta inicial" é o tempo entre a detecção/reporte e um humano confirmar que está tratando o incidente — não o tempo até a resolução completa, que varia por natureza do problema. ## Fluxo Via alerta automatizado (quando existir — hoje não há detecção de anomalias automatizada; ver a seção "Defesa & resposta" em [Segurança — visão geral](/security/overview)), reporte de parceiro, reporte via [divulgação de vulnerabilidade](/security/vulnerability-disclosure), ou reporte interno. Ação imediata para limitar o dano — revogar credencial comprometida, desabilitar rota afetada, isolar o recurso. O objetivo da contenção é parar o incidente de piorar, não corrigir a causa raiz ainda. Se o incidente afeta um parceiro integrado (ex: indisponibilidade da API, atraso de entitlement), ele é notificado pelo canal técnico definido no contrato de parceria com os responsáveis técnicos de cada lado. Se o incidente envolve dados pessoais, ver a seção **LGPD e a ANPD** abaixo — esse é um fluxo com regras próprias, não uma decisão discricionária de relacionamento com o parceiro. Registro por escrito: linha do tempo, causa raiz, o que funcionou na resposta e o que não funcionou. O objetivo é o processo, não encontrar quem errou — isso é o que faz as pessoas reportarem incidentes em vez de escondê-los. Item de ação com dono e prazo, rastreado até fechar. Para incidentes P1/P2, a ação corretiva é parte do relatório enviado ao parceiro afetado. ## LGPD e a ANPD: quando e como comunicar A LGPD (Lei 13.709/2018) **não fixa um prazo numérico** para comunicação de incidente — isso é frequentemente confundido com o GDPR europeu, que define 72 horas. O Art. 48 da LGPD determina que o controlador comunique à Autoridade Nacional de Proteção de Dados (ANPD) e ao titular a ocorrência de incidente de segurança que possa acarretar risco ou dano relevante, em **prazo razoável**, conforme definido pela ANPD — sem um número fixo na própria lei. A Googa não promete "72 horas" nem qualquer outro número específico como obrigação legal; o compromisso operacional de tempos de resposta acima (15 min para P1) é sobre a resposta ao incidente, não sobre o prazo legal de comunicação à ANPD, que segue o critério de razoabilidade da autoridade e a gravidade do caso concreto. Um incidente aciona esse fluxo de comunicação externa quando envolve dados pessoais (Art. 5º, I e II) e há risco ou dano relevante aos titulares — não todo incidente técnico exige isso. Quando aplicável: 1. **Avaliação de risco** — natureza do dado exposto (dado comum vs. sensível vs. de criança/ adolescente, este último com atenção redobrada — ver [Proteção de dados de menores](/security/child-data-eca)), volume de titulares afetados, e se o dado foi de fato acessado por terceiro não autorizado ou apenas potencialmente exposto. 2. **Comunicação ao DPO** (`privacy@googa.com.br` — ver [LGPD](/security/lgpd#dpo)) para decidir, junto à liderança técnica, se o caso configura risco ou dano relevante nos termos do Art. 48. 3. **Comunicação à ANPD e aos titulares afetados**, em prazo razoável, com a natureza dos dados afetados, as medidas técnicas de segurança utilizadas, os riscos relacionados ao incidente e as medidas adotadas para reverter ou mitigar os efeitos — o conteúdo mínimo exigido pelo próprio Art. 48. 4. **Se o parceiro (Algar ou outro) for o controlador da relação com o assinante final** (ver o detalhamento de papéis em [LGPD — bases legais](/security/lgpd)), a Googa comunica o parceiro sem demora, para que ele cumpra suas próprias obrigações como controlador perante os titulares com quem tem a relação direta. Este fluxo formal de comunicação à ANPD ainda não foi exercitado em produção — é o desenho correto de acordo com a lei, proposto para ser seguido quando (e se) um incidente elegível ocorrer. # LGPD — bases legais, direitos e governança de dados Source: https://developers.googa.com.br/security/lgpd Como a Lei 13.709/2018 se aplica a cada relação de tratamento da Googa — bases legais, papéis (controlador/operador), direitos do titular, retenção, DPO, RIPD e transferência internacional. Esta página cita artigos específicos da LGPD (Lei 13.709/2018) e distingue, para cada compromisso, o que já está operacionalizado (**GA**) do que é desenho proposto (**Roadmap**). Onde não temos certeza sobre um fato técnico (ex: região física de hospedagem), marcamos como ponto de atenção em vez de assumir. ## Bases legais por relação de tratamento (Art. 7º) A LGPD exige uma base legal específica por finalidade — não existe uma base legal única "da empresa". A Googa trata dados pessoais em (pelo menos) três relações diferentes, cada uma com sua própria base: **Consentimento** (Art. 7º, I) para perfil e preferências (gênero de leitura, interesses da criança, faixa etária) — coletado no cadastro, revogável a qualquer momento (ver [Direitos do titular](#direitos-do-titular-art-18) abaixo). **Execução de contrato** (Art. 7º, V) para os dados estritamente necessários a prestar o serviço assinado — progresso de leitura, status de assinatura, e-mail para autenticação. **Execução de contrato entre empresas** (Art. 7º, V) e **legítimo interesse** (Art. 7º, IX) para o repasse de billing agregado e entitlements — esta relação **não depende do consentimento individual do assinante final** para existir, porque o dado trocado entre Googa e o parceiro nesta camada é operacional (status de assinatura, contagem de exemplares ativos), não o conteúdo de leitura ou o perfil comportamental do assinante. **Consentimento parental específico e em destaque** (Art. 14, §1º) para o tratamento de dado de criança — dado por pelo menos um dos pais ou responsável legal, nunca pela própria criança. É uma relação própria, distinta da relação B2C com o adulto titular da conta, com regras, retenção e restrições reforçadas — ver [Proteção de dados de menores (ECA)](/security/child-data-eca), incluindo o gap identificado no texto de consentimento da tela de cadastro. ### Quem é controlador, quem é operador — a distinção que evita ambiguidade Este é o ponto que costuma ficar implícito (e errado) em respostas de licitação: nossa leitura é que, na relação com o assinante final da Algar, * **a Algar é a controladora** da relação com o próprio assinante — é ela que tem o contrato de telecomunicações com essa pessoa, que decide oferecer o SVA, e que responde primariamente diante do assinante por essa relação; * **a Googa atua como operadora** (Art. 5º, VII) de uma parte específica do tratamento: a entrega do conteúdo (livro, história, áudio) e a telemetria de uso desse conteúdo, processada sob instruções e finalidade definidas em contrato com a Algar. Isso significa que a Googa trata dado do assinante da Algar **em nome** da Algar, dentro do escopo contratado — não como controladora independente decidindo por conta própria o que fazer com o dado desse assinante. Onde a Googa também define finalidades próprias sobre o mesmo dado (ex: melhorar o modelo de recomendação entre produtos, cross-produto), ela atua como controladora **daquele** tratamento específico — a LGPD permite que a mesma pessoa jurídica seja operadora de um tratamento e controladora de outro, desde que a finalidade e o escopo de cada um estejam claros no contrato. Isso deve estar refletido no contrato de parceria (não só nesta documentação): quem decide o quê, sobre qual subconjunto de dado, é o que define o papel — não o rótulo que se dá à relação. ## Direitos do titular (Art. 18) | Direito (Art. 18) | Como é operacionalizado hoje | Status | | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | | Confirmação da existência de tratamento | Suporte por e-mail responde manualmente | GA (manual) | | Acesso aos dados | RPC `export_my_data()` — devolve JSON com tudo que a conta/família tem em cada tabela relevante, respeitando RLS por trás mesmo dentro da função | **GA** (NovelAI/NovelÁudio e HistorinhAI) | | Correção de dados incompletos/inexatos | Editável direto no app (perfil, preferências, perfil de criança) | GA | | Anonimização, bloqueio ou eliminação de dado desnecessário/excessivo | Exclusão de conta cobre isto — ver linha abaixo. Anonimização automática de dado retido por obrigação legal é Roadmap (ver [Retenção](#retenção)) | Parcial | | Portabilidade a outro fornecedor | O JSON de `export_my_data()` é a base; formato padronizado entre fornecedores de mercado ainda não existe (nem na LGPD, nem por convenção de mercado neste setor) | GA (exportação) / Roadmap (portabilidade padronizada) | | Eliminação dos dados tratados com consentimento | RPC `delete_my_account()` — apaga a conta e cascateia a maior parte dos dados via `on delete cascade` de `auth.users`; no HistorinhAI, reatribui dados de família antes de apagar para não afetar outros membros (ver [Mapeamento de dados](/security/data-processing)) | **GA** | | Informação sobre compartilhamento (com quem, e por quê) | Documentado nesta página e em [Mapeamento de dados](/security/data-processing); não há hoje um portal de autoatendimento — é resposta manual via `privacy@googa.com.br` | Parcial | | Revogação do consentimento | Hoje via exclusão de conta ou contato manual. Um controle granular ("revogar só o consentimento de recomendação personalizada, manter a conta") é **Roadmap** | Parcial | ## Minimização e finalidade (Art. 6º) O Art. 6º exige que o tratamento seja limitado ao mínimo necessário para a finalidade informada (inciso III, minimização) e realizado para propósitos legítimos e específicos (inciso I, finalidade). O que coletamos, por produto: * **Todos os produtos**: e-mail (autenticação), status de assinatura, telemetria de uso do próprio conteúdo (progresso, capítulo aberto) — necessário para a própria mecânica do produto (desbloqueio diário, retomada de posição), não coletado "porque pode ser útil depois". * **NovelAI**: gênero de leitura preferido, histórico de escolhas de final (mecânica exclusiva desse produto — HistorinhAI e NovelÁudio têm desfecho único e fixo) — usado para recomendação dentro do próprio produto. * **NovelÁudio**: gênero de escuta preferido — usado para recomendação dentro do próprio produto. * **HistorinhAI**: idade e interesses da criança, desafio do mês, competências mapeadas por história (empatia, vocabulário...) — estritamente o necessário para gerar a história certa e o relatório mensal aos pais. Ver tratamento reforçado em [Proteção de dados de menores](/security/child-data-eca). Não coletamos geolocalização precisa, contatos do dispositivo, nem dado de terceiros não titulares da conta. Dado de comportamento (device, horário de sessão) descrito na proposta técnica como insumo de personalização é usado apenas em agregado para a métrica do próprio produto — não é vendido nem repassado a terceiros para fins de publicidade. ## Retenção Propomos os seguintes prazos, sujeitos a revisão à medida que o RIPD (abaixo) for formalizado: | Categoria de dado | Prazo proposto | Justificativa | | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Telemetria/sessão de leitura granular (evento por evento) | 12 meses, depois agregado/anonimizado | Suficiente para o próprio produto (relatório mensal, recomendação) sem acumular histórico comportamental indefinido | | Dados de conta após cancelamento (sem exclusão explícita pelo titular) | 90 dias em estado inativo, depois anonimização das colunas identificáveis | Janela para reativação sem fricção, sem manter identidade vinculada indefinidamente | | Exclusão de conta a pedido do titular | Imediata para o que não tem obrigação legal de guarda (ver `delete_my_account()`) | Atende ao Art. 18, VI diretamente | | Dados financeiros/fiscais (nota de débito, registro de cobrança) | Prazo de guarda fiscal aplicável (mínimo 5 anos, conforme legislação tributária) | Obrigação legal (Art. 7º, II da LGPD permite tratamento para cumprimento de obrigação legal) prevalece sobre o pedido de exclusão para **esse subconjunto** de dado — o resto da conta é excluído normalmente | | Dados de criança no HistorinhAI | Ver prazo específico, mais curto, em [Proteção de dados de menores](/security/child-data-eca#retenção-mais-curta-e-específica) | Tratamento reforçado por envolver Art. 14 da LGPD e o ECA | Estes prazos são a proposta atual da Googa — ainda não estão todos automatizados (a anonimização programática após os 90 dias de conta inativa, por exemplo, é **Roadmap**; a exclusão imediata a pedido já é **GA**). ## DPO A Googa designa um Encarregado de Proteção de Dados (DPO, Art. 5º, VIII e Art. 41), conforme já indicado na proposta técnica GoogaBooks. Canal de contato: **`privacy@googa.com.br`**. É por esse canal que titulares exercem os direitos do Art. 18 hoje tratados manualmente, e por onde a ANPD ou um parceiro deve ser direcionado em caso de dúvida sobre tratamento de dados. ## RIPD — Relatório de Impacto à Proteção de Dados (Art. 5º, XVII e Art. 38 da LGPD.) O RIPD é exigido (a critério da ANPD, ou proativamente quando o tratamento envolve alto risco às liberdades civis e aos direitos fundamentais) quando o tratamento é de alto risco. Nossa avaliação: * **HistorinhAI exige RIPD.** Trata dado de criança e adolescente (Art. 14) em escala, incluindo competências comportamentais mapeadas por perfil — isso é tratamento de alto risco pela própria natureza do titular (criança) e pela granularidade do dado (relatório de desenvolvimento). * **NovelAI/NovelÁudio**: risco menor (adultos, dado de preferência de leitura, sem dado sensível no sentido do Art. 5º, II) — RIPD não é obrigatório hoje, mas pode ser revisitado se a personalização evoluir para usar dado sensível (ex: inferência de orientação, saúde mental). O RIPD do HistorinhAI é um compromisso de manter **atualizado**, não um documento estático — revisado a cada mudança relevante no tratamento (novo tipo de dado coletado, nova finalidade, novo sub-processador). Hoje esse relatório formal ainda não existe como documento único — é **Roadmap** produzi-lo e mantê-lo, com o conteúdo desta página e de [Proteção de dados de menores](/security/child-data-eca) como insumo direto. ## Transferência internacional (Art. 33) **Ponto de atenção — não temos confirmação da região física de hospedagem de cada projeto Supabase.** Não vamos assumir que os dados estão em território brasileiro sem verificar isso no painel de cada projeto. Este é um item a confirmar (e, se necessário, corrigir) antes de qualquer compromisso contratual formal com um parceiro que exija dado em território nacional. Dois pontos de transferência internacional relevantes, tratados com honestidade em vez de suposição: 1. **Infraestrutura Supabase**: o Supabase oferece hospedagem em múltiplas regiões, incluindo `sa-east-1` (São Paulo). Se algum projeto Googa estiver hospedado fora do Brasil, isso é uma transferência internacional de dado pessoal sujeita ao Art. 33 — exigindo uma das hipóteses do artigo (ex: cláusulas contratuais padrão, ou garantias equivalentes fornecidas pelo Supabase como operador). Ação proposta: confirmar a região de cada projeto e, quando disponível e ainda não configurado, migrar para a região São Paulo/Brasil. 2. **Provedores de modelo de linguagem (LLM/TTS)**: a geração de conteúdo assistida por IA e a síntese de voz hoje passam por gateways de modelo de terceiros (as Edge Functions `tts` vivem nos projetos "Novel" — compartilhado por NovelAI/NovelÁudio — e "HistorinhAI") cuja infraestrutura de inferência não é necessariamente brasileira. Isso é, com alta probabilidade, uma transferência internacional para o texto/áudio processado — tratada via os termos contratuais do próprio provedor de modelo. Não confirmamos se esses termos incluem cláusulas contratuais padrão equivalentes às exigidas pela LGPD; isso é **ponto de atenção**, não uma garantia que damos aqui. Onde a transferência internacional for confirmada e não puder ser evitada, o caminho correto (Art. 33, I) é cláusulas contratuais padrão ou cláusulas específicas para a transferência, aprovadas pela ANPD, ou comprovação de que o país/organização de destino oferece grau de proteção adequado — não apenas assumir que "a nuvem é global e está tudo bem". # Segurança da informação — visão geral Source: https://developers.googa.com.br/security/overview Criptografia, isolamento multi-tenant e defesa em profundidade: o que já está em produção hoje e o que é desenho de destino. As medidas citadas abaixo refletem o estado real em produção hoje — não uma promessa genérica de compliance. ## Criptografia Toda comunicação entre app/cliente e a API — hoje servida diretamente pelo [Supabase](https://supabase.com) (PostgREST, Auth, Edge Functions) — é criptografada com TLS, terminado na borda da infraestrutura do provedor. É nativo do Supabase, não uma configuração que a Googa precisa manter manualmente: não há endpoint HTTP sem TLS em nenhum produto. O Postgres de cada projeto Supabase roda sobre disco criptografado por padrão pelo provedor de nuvem subjacente (criptografia de volume, AES-256) — isso vale para todos os três projetos (Novel, HistorinhAI, e o projeto Platform — já existente no código, com deploy em produção pendente). A Googa não precisa (e hoje não configura) nada adicional para que o dado em disco esteja cifrado. As chaves de criptografia em repouso são geridas pelo KMS do provedor de nuvem que sustenta o Supabase — não por um KMS operado diretamente pela Googa. Isso é adequado para o nível de risco atual, mas vale registrar com transparência: a Googa hoje **não** possui uma chave própria (CMK/BYOK) sobre esse material, então a rotação e as políticas de chave seguem o padrão do provedor, não uma política definida pela Googa. Uma central de secrets própria por aplicação (para credenciais de parceiro, chaves de LLM, etc. — separado do KMS de disco) ainda não existe hoje — ver [Modelo de autenticação](/architecture/supabase-auth-model) para o desenho do Partner Gateway. ## Isolamento & controle de acesso RLS do Postgres é a linha de defesa principal em produção hoje, em todos os projetos: cada política filtra por `auth.uid()` (leitor) ou por `family_id`/`partner_id` resolvido server-side — nunca por um valor que o próprio cliente envia na requisição. Esse controle passa por auditoria ativa, não só por um desenho único no início do projeto: * Em `historinhai`, a policy de insert de `reading_sessions` exige consistência entre `family_id` e `child_id` — um usuário autenticado só consegue gravar uma sessão apontando para um `child_id` que pertence à mesma família informada, o que evita poluição de dado entre famílias. * Em `novelai`/`novelaudio`, toda função `security definer` (incluindo `remove_reading_progress`) roda com `search_path = ''` e qualifica tudo explicitamente por `public.` — o padrão adotado em todo o projeto como defesa em profundidade contra *search\_path hijacking* em funções que rodam com privilégio elevado. NovelAI e NovelÁudio compartilham um projeto Supabase; HistorinhAI roda em um projeto inteiramente separado — decisão deliberada dado o tratamento de dados de crianças (ver [Proteção de dados de menores](/security/child-data-eca)). Não existe hoje nenhuma consulta cross-projeto no nível de banco: qualquer travessia entre produtos passa por uma Edge Function que valida a chamada de novo. As Edge Functions de TTS, e-mail e geração de URL assinada de áudio respondem com uma allowlist explícita de origem, não com `Access-Control-Allow-Origin: *`. A autenticação real é por header `Authorization` (JWT), não por cookie — então CORS aberto não permitiria forjar sessão de outra origem — mas a allowlist é mantida como defesa em profundidade: evita que qualquer site arbitrário chame esses endpoints pagos (TTS, e-mail, signed URL de áudio) em nome de um usuário já autenticado em outra aba. A função `generate_short_code` — usada para código de convite de família e de indicação/promo — usa `gen_random_bytes()` (extensão `pgcrypto`), um CSPRNG de verdade, e não `random()` do Postgres, que não é criptograficamente seguro. Relevante porque um código previsível de convite de família permitiria a um atacante entrar em uma família de terceiros sem ser convidado. Escopos diferenciados por parceiro e por rota estão implementados no Partner Gateway: cada endpoint exige um escopo específico (`entitlements:write`, `subscriber:read`, `billing:read`), verificado contra os escopos gravados na credencial do parceiro — um token sem o escopo da rota recebe `403`. Ver [Modelo de autenticação](/architecture/supabase-auth-model#partner-gateway-a-camada-que-conecta-as-duas-pontas). O que ainda não existe é isso rodando em produção — o deploy do Partner Gateway está pendente; até lá, o único controle de acesso em produção é o do usuário final do produto. ## Defesa & resposta O site institucional (`googa.com.br`) já publica cabeçalhos de segurança na borda (`X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`, `Content-Security-Policy` restritiva, `Referrer-Policy: strict-origin-when-cross-origin`) via `public/_headers` do provedor de hospedagem. Isso é real e está em produção — mas é a borda do site estático, não da API. A API em si (PostgREST/Edge Functions do Supabase) hoje só tem o rate-limit interno do próprio Supabase para proteção da plataforma, não um rate-limit configurável por parceiro/rota. A Googa **não opera hoje** um WAF dedicado, um SIEM, ou um programa de pentest periódico contratado — além do que a própria infraestrutura de hospedagem/Supabase já aplica para proteção geral da plataforma. O desenho para fechar essa lacuna é um proxy de borda (Cloudflare, à frente do Custom Domain do Supabase — ver [Modelo de autenticação](/architecture/supabase-auth-model)) fazendo WAF gerenciado e rate-limit por token de API antes de chegar ao backend, mais um ciclo de pentest externo contratado antes do go-live com qualquer parceiro enterprise. Hoje a operação é pequena o suficiente para não ter um SOC 24×7 nem alertas de anomalia automatizados de segurança. O processo de resposta a incidentes descrito em [Resposta a incidentes](/security/incident-response) é o desenho que operacionaliza o compromisso de SLA (P1 em 15 minutos) — não uma prática já rodando com essa maturidade. ## Alinhamento a padrões A Googa segue os controles da **ISO 27001** como referência de boas práticas de gestão de segurança da informação — isso significa **alinhamento aos controles**, não uma certificação ISO 27001 obtida por auditoria de terceira parte. Não há certificação a apresentar hoje — onde um processo de licitação exigir evidência de certificação formal, isso não é algo que a Googa possa reivindicar como já obtido. Severidade, tempos de resposta e o fluxo de comunicação — incluindo quando um incidente aciona notificação à ANPD. Base legal, direitos do titular, retenção, DPO, RIPD e transferência internacional — artigo por artigo. # Política de Privacidade da API Source: https://developers.googa.com.br/security/privacy-policy Como a Googa trata dados pessoais especificamente no fluxo de integração via API de parceiro — papéis de controlador/operador, dados trafegados, retenção e direitos do titular. **Rascunho técnico — pendente de revisão jurídica formal.** Este documento foi redigido pela equipe técnica da Googa como base real para a Política de Privacidade da API, no formato e com o nível de detalhe de uma Privacy Policy de API enterprise. Ele **não é** um instrumento jurídico já validado por advogado nem passou por análise formal de DPO — está publicado aqui para fins de avaliação técnica no âmbito do RFP Livros Digitais 2026 (Algar Telecom) e para servir de insumo à revisão jurídica que precisa correr antes de se tornar vinculante. Ela deve ser lida em conjunto com [Privacidade & LGPD](/security/lgpd) e com a [Política de Uso da API](/security/api-usage-policy). ## 1. Escopo Esta política trata **exclusivamente** dos dados que trafegam pela API de parceiro Googa — as chamadas de servidor-a-servidor entre o sistema de um parceiro integrador (ex.: o backend da Algar) e as APIs Platform, NovelAI, HistorinhAI e NovelÁudio, incluindo entitlements, status de assinante, uso para billing, webhooks e SSO. Ela **não é** a política de privacidade do aplicativo para o usuário final — cada produto Googa (NovelAI, HistorinhAI, NovelÁudio) tem sua própria política de privacidade voltada ao leitor/ assinante final, publicada dentro do respectivo app, que cobre o tratamento completo de dados dentro do produto (cadastro, uso do app, preferências, etc.). Esta política de API **complementa** aquelas políticas no ponto específico em que um dado cruza a fronteira entre o sistema do parceiro e a Googa — ela não as substitui nem reduz o alcance delas. ## 2. Papéis (controlador e operador) O papel de cada parte varia conforme o fluxo de dado, e é importante não tratar "Algar" e "Googa" como um único papel fixo: | Fluxo | Controlador (LGPD art. 5º, VI) | Operador (LGPD art. 5º, VII) | | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | Relação comercial e cadastral do assinante com o Parceiro (plano, fatura, atendimento) | **Parceiro** (ex.: Algar) | — | | Entrega do conteúdo/serviço contratado ao assinante via API (entitlement, catálogo, progresso) | **Parceiro**, em relação ao próprio assinante | **Googa**, atuando por instrução do Parceiro para viabilizar a entrega do serviço contratado | | Geração/curadoria do conteúdo editorial (obras, metadados, ISBN) | **Googa** | — | | Relatório de desenvolvimento infantil do HistorinhAI enviado aos pais | **Googa**, em relação ao perfil da criança criado dentro do próprio app (fora do fluxo de API de parceiro) | — | Em resumo: para o dado do assinante que entra e sai pela API de parceiro, a Algar é controladora da relação com o assinante final, e a Googa é operadora do tratamento necessário para entregar o conteúdo/serviço contratado — a Googa trata esse dado nos limites definidos pelo Contrato de Parceria e por instrução do Parceiro, e não para finalidade própria alheia a essa entrega. Este mapeamento segue os mesmos princípios definidos em [Privacidade & LGPD](/security/lgpd). ## 3. Dados tratados via API A API de parceiro é desenhada para trafegar o **mínimo necessário** para operar entitlement, billing e SSO — nunca dado de contato ou dado de leitura individualmente identificável fora do estritamente necessário. **Do Parceiro para a Googa** (ex.: `POST /entitlements`, parâmetros de consulta de `GET /billing-usage`): | Campo | Descrição | | --------------- | ------------------------------------------------------------------------------------------------------------ | | `subscriber_id` | Identificador do assinante **no sistema do Parceiro** — não é um dado de contato, é uma chave técnica opaca. | | `product` | Qual produto Googa (`novelai`, `novelaudio`, `historinhai`) o entitlement se refere. | | `plan` | Plano contratado pelo assinante no Parceiro, mapeado para um plano interno Googa. | | `status` | `active`, `suspended` ou `canceled`. | **Da Googa para o Parceiro** (ex.: resposta de `GET /subscriber-status/{id}`, webhooks `subscriber.updated`/`subscription.canceled`, resposta de `GET /billing-usage`): * Os mesmos campos acima, refletidos de volta (`subscriber_id`, `product`, `plan`, `status`, `updated_at`); * Dados **agregados** de billing e uso — contagem de exemplares/assinantes ativos por produto (`active_count`) — nunca um relatório de leitura individualmente identificável de um assinante específico. A API de parceiro **nunca expõe e-mail, nome completo, CPF ou qualquer dado de contato do assinante.** A Googa não recebe esses dados do Parceiro através desta API além do identificador técnico `subscriber_id`, e não os devolve em nenhuma resposta ou webhook. Qualquer necessidade de contato direto com o assinante (ex.: cobrança, atendimento) permanece inteiramente do lado do Parceiro, que é o controlador dessa relação. ## 4. Dados de crianças (HistorinhAI) Reforçando o que já vale para toda a plataforma: **nenhum dado identificável de criança trafega pela API de parceiro.** O `subscriber_id` do HistorinhAI identifica a conta do responsável (assinante), não a criança — perfis infantis, idade, interesses, desafios do mês e o relatório de desenvolvimento mensal são geridos inteiramente dentro do app, sob controle parental, e não são campos expostos por nenhum endpoint desta API. Ver [Proteção de dados de menores — ECA](/security/child-data-eca) para o tratamento completo. ## 5. Retenção dos dados de integração Logs de chamadas de API (requisição, resposta, timestamps, credencial usada — não o corpo de dados de negócio além dos campos da seção 3) são retidos por **12 meses**, prazo dimensionado para cobrir auditoria de billing (reconciliação de Nota de Débito, contestação de cobrança) e investigação de incidentes de segurança dentro de uma janela razoável. Após esse prazo, os logs são anonimizados ou agregados (ex.: métricas de volume por parceiro/período) e os registros individuais são descartados. Eventos de webhook não são retidos além do necessário para registrar o resultado da entrega — não existe fila própria de reenvio (a entrega é feita em uma única tentativa por disparo; ver [Platform API — Eventos](/platform/overview#eventos-webhooks-de-saída)). ## 6. Segurança em trânsito e repouso Os controles técnicos de criptografia em trânsito (TLS 1.3), em repouso (AES-256, com chaves geridas pelo KMS do provedor de nuvem subjacente — a Googa não opera CMK/BYOK própria), segregação de ambientes e princípio de menor privilégio aplicáveis a toda a plataforma — incluindo o tráfego desta API — estão descritos em [Segurança da informação — visão geral](/security/overview). ## 7. Direitos do titular no contexto da API Um assinante final que queira exercer direitos previstos na LGPD (confirmação de tratamento, acesso, correção, exclusão, portabilidade, entre outros) em relação a dados que trafegaram por uma integração de parceiro deve, como regra, acionar **o canal do Parceiro** — é o Parceiro que mantém a relação direta e o dever de resposta ao titular, na condição de controlador dessa relação (ver [Papéis](#2-papéis-controlador-e-operador)). O fluxo típico é: 1. O assinante solicita o exercício do direito diretamente ao Parceiro (ex.: canal de atendimento Algar / Minha Algar). 2. O Parceiro, de posse do `subscriber_id`, repassa a solicitação à Googa — via a própria API (quando o direito puder ser atendido por uma chamada, ex.: suspensão de entitlement) ou via o canal de suporte a parceiros (para solicitações que exigem ação manual, como exclusão de dados de leitura associados a um `subscriber_id`). 3. A Googa atende a solicitação nos limites do que efetivamente processa como operadora — dados sob controle exclusivo do Parceiro (cadastro, contato, fatura) não são detidos pela Googa e não podem ser atendidos por ela. A Googa também mantém um canal direto para o encarregado (ver [Contato do encarregado (DPO)](#9-contato-do-encarregado-dpo)) para os casos em que o titular já é conhecido diretamente pela Googa fora do fluxo de parceiro (ex.: usuário do app oficial). ## 8. Sub-processadores A Googa utiliza os seguintes sub-processadores no tratamento de dados relacionados à integração de parceiro: * **[Supabase](https://supabase.com)** — infraestrutura de dados (banco de dados Postgres, autenticação e funções de borda) de cada produto. Ver [Modelo de autenticação sobre Supabase](/architecture/supabase-auth-model) para o desenho de isolamento entre produtos e entre parceiros. * **Provedor(es) de LLM (modelo de linguagem) de terceiros**, contratado(s) para geração e adaptação assistida de conteúdo editorial (texto e roteiro de narração). É importante ser preciso aqui: esse processamento tem como entrada o **texto da obra e metadados editoriais** (gênero, arco narrativo, faixa etária de destino) — não processa dados pessoais do leitor/assinante. Os sinais de personalização (histórico de leitura, preferências) usados para *selecionar* qual obra recomendar são tratados nos sistemas de domínio da Googa, e não são enviados ao provedor de LLM como parte da geração de conteúdo. ## 9. Contato do encarregado (DPO) Solicitações relacionadas a esta política, exercício de direitos do titular ou incidentes envolvendo dados tratados no contexto da API de parceiro: [privacy@googa.com.br](mailto:privacy@googa.com.br). ## 10. Vigência e alterações Esta política entra em vigor na data de publicação e é revisada sempre que houver mudança relevante no desenho da API de parceiro, nos sub-processadores utilizados, ou na legislação aplicável. Alterações materiais seguem o mesmo regime de aviso prévio definido na [Política de Uso da API](/security/api-usage-policy#9-alterações-a-esta-política). # Divulgação responsável de vulnerabilidades Source: https://developers.googa.com.br/security/vulnerability-disclosure Como reportar uma vulnerabilidade de segurança encontrada em qualquer produto ou API da Googa, e o que esperamos em troca. Esta política cobre NovelAI, HistorinhAI, NovelÁudio, o site institucional e a API de parceiro (quando entrar em produção). Não existe hoje um programa de recompensa financeira — ver a seção **Programa de recompensa** abaixo. ## Como reportar Envie um e-mail para **`security@googa.com.br`** com: * Descrição da vulnerabilidade e impacto potencial. * Passos para reproduzir (ou uma prova de conceito mínima). * Produto/URL/endpoint afetado. * Se possível, uma sugestão de mitigação. Não é necessário criptografar o e-mail para o primeiro contato. Se o conteúdo do reporte envolver dado pessoal de terceiro (ex: você encontrou dado de outro usuário exposto), inclua o mínimo necessário para comprovar o problema — não anexe uma exportação completa do que você encontrou. ## O que pedimos que você não faça * **Engenharia social** contra funcionários, suporte ou usuários da Googa. * **Acesso, cópia ou retenção de dados de terceiros** além do mínimo necessário para provar a vulnerabilidade. Se você acessou dado real de outro usuário incidentalmente, reporte isso explicitamente e não o mantenha. * **Negação de serviço** (DoS/DDoS), testes de carga, ou qualquer ação que degrade a disponibilidade do serviço para outros usuários. * **Testes contra dados de crianças no HistorinhAI** que exijam criar ou manipular perfis de criança reais — se sua pesquisa precisa de um ambiente de teste, peça acesso a sandbox pelo mesmo e-mail em vez de usar contas reais. * Divulgação pública da vulnerabilidade antes de combinarmos um prazo de correção com você (*coordinated disclosure*). Seguindo essas diretrizes, a Googa não vai buscar ação legal contra a pesquisa de boa fé. ## Nosso compromisso de resposta | Etapa | Prazo | | ------------------------------------------ | --------------------------------- | | Confirmação de recebimento | 2 dias úteis | | Triagem inicial (validação + severidade) | 5 dias úteis | | Atualização de status, mesmo sem resolução | A cada 2 semanas até o fechamento | Vulnerabilidades classificadas como P1/P2 (ver [Resposta a incidentes](/security/incident-response)) seguem os tempos de contenção daquela página a partir da confirmação. ## Programa de recompensa **Não existe hoje um programa de bug bounty remunerado.** Reportes recebidos e validados são reconhecidos publicamente (com consentimento de quem reportou) e, quando aplicável, tratados com prioridade nas próximas etapas de contratação/parceria de segurança. Um programa de recompensa formal (com tabela de valores por severidade) é **Roadmap** — depende de um orçamento e um processo de triagem dedicados que a operação atual, ainda pequena, não sustenta. Não prometemos pagamento por reporte enquanto isso não existir formalmente.