# 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.