gclinic — Plataforma Cloudflare

Plataforma SaaS de clínicas médicas rodando 100% em Cloudflare Workers. 5 produtos publicados em repos independentes, arquitetura de 3 camadas (R1/R2/R3), filas, Durable Objects e OpenAI Responses API.

Clique em qualquer card para explicacao detalhada
5
Sub-projetos
3
Camadas (R1/R2/R3)
10+
Workers Cloudflare
9
Filas (Queues)
2
Durable Objects
4
Tool Executors
gpt-5.4
Modelo default
🏮 Visao Geral — 5 Produtos Independentes
gclinic NAO e uma aplicacao única. São 5 produtos independentes, cada um publicado em seu próprio repo, rodando em Cloudflare Workers e conectados por Service Bindings, Queues e uma API central de autenticação. Localmente, a pasta agrupa todos por conveniencia.
gclinicFrontend + API clínica
gagentsAI agent orchestrator
gchatMessaging gateway
gauthCentral auth (JWT)
gadminSuperadmin panel
📦 Os 5 Produtos
Cada produto tem seus próprios r1/r2/r3 e seu próprio schema package npm. Clique para detalhes.
🔑

gauth

Serviço central de autenticação. Emite JWTs usados por TODOS os outros produtos. Users, accounts, profiles.

WorkersPostgres
🚑

gclinic (produto)

Plataforma clínica: pacientes, consultas, profissionais, agendas, convênios, sincronia Google Calendar.

Next.js 16Workers
💬

gchat

Gateway multi-canal (WhatsApp, SMS). Substitui o Chatwoot. Adapters pluggable, queues, webhooks.

WorkersGo (whatsmeow)
🤖

gagents

Orquestrador de agentes IA. OpenAI Responses API, Durable Objects, tool execution engine, followups agendados.

OpenAIDurable Objects
🛡

gadmin

Painel superadmin para operadores da plataforma. Gerência accounts, usuários, produtos, integrações.

Next.js 16
📚 Padrão R1/R2/R3 — O Conceito Central
Cada produto segue a mesma estrutura de 3 camadas. Clique em cada camada para entender.
R1

Database Layer

Um Worker dedicado que abstrai TODO acesso ao Postgres.

  • Endpoint único POST /
  • Recebe objetos de operação (SELECT, INSERT, ...)
  • Acessa Postgres via Hyperdrive
  • Chamado via Service Binding
R2

Storage/Queue Layer

Workers para R2 buckets e/ou consumers de Cloudflare Queues.

  • Upload de imagens (fotos de pacientes)
  • Arquivos de áudio transcritos
  • Consumers de filas assincronas
R3

Business Logic

Workers REST API que expoe a logica de negocio. Divididos em r3-api (backend) e r3-app (frontend).

  • r3-api: REST routes + services
  • r3-app: Next.js 16 SPA
  • Consome r1 via service binding
🧠 Stack Tecnologico (clique para explicar)
Cada peca do stack explicada em linguagem clara.
Cloudflare Workers
Serverless V8 isolates
Hyperdrive
Postgres proxy para Workers
Durable Objects
Compute com estado
Cloudflare Queues
Fila assincrona managed
R2 Buckets
Object storage (S3-compat)
Workers KV
Key-value distribuido
Workers AI
Inference na rede Cloudflare
Service Bindings
Worker → Worker sem HTTP
Wrangler
CLI de deploy
@opennextjs/cloudflare
Next.js → Workers adapter
Next.js 16
App Router + RSC
React 19
Actions + useOptimistic
bun
Package manager + runtime
better-auth
Auth framework TS
postgres.js
Driver Postgres ESM
OpenAI Responses API
Sucessor do Assistants API
TanStack Query v5
Server state caching
Zustand
Client state store
whatsmeow (Go)
Bridge WhatsApp não-oficial
Fly.io
Deploy do serviço Go
Tabler Icons
Biblioteca de icones
shadcn/ui
Componentes copy-paste
Tailwind v4
CSS utility-first
Vitest
Test runner
Playwright
E2E browser tests
📦 Biblioteca Interna @greatapps/*
10+ pacotes npm compartilhados entre todos os produtos. Padronizam roteamento, DB, cache, JWT, HTTP, validação.
📦

@greatapps/router

Framework HTTP estilo Express para Workers, com middleware injection e queues.

📦

@greatapps/api

Camada CRUD que consome r1-api-postgresql. Métodos insert, update, view, delete, restore.

📦

@greatapps/schema

Validação e type coercion. Define entidades com tipos, validations e multi-tenancy.

📦

@greatapps/jwt

Encode/decode JWT via Web Crypto API (nativa no Workers runtime).

📦

@greatapps/cache

Cache distribuido backed por KV. TTLs, invalidacao por prefixo.

📦

@greatapps/fetch

HTTP client com retry automático, caching e timeout.

📦

@greatapps/queue

Fila com controle de concorrência para executar N tarefas async.

📦

@greatapps/utils

Crypto, string, date, UUID. Utilitarios compartilhados.

📦

@greatapps/crypt

Encode/decode de strings para comunicação inter-serviços.

📦

@greatapps/greatauth-ui + greatchat-ui + greatagents-ui

Componentes React compartilhados: login, app shell, inbox, composer, dashboard de agentes.

🔌 Fluxo Completo — Mensagem chega até o agente
Clique em cada caixa para entender o papel específico.
📱 WhatsAppvia Meta Cloud
🧭 whatsmeowGo (Fly.io)
📤 gchat-r3-apiWebhook + adapter
↓ queue
⚡ gchat-r2-inbound-messageCloudflare Queue
🤖 gagents-r3-apiconsumer
🎞 MessageAggregatorDurable Object
⚡ receive-message-normalizedQueue
🧠 OpenAI Responses APIgpt-5.4-mini
🔧 ToolExecutionEngine4 executors
⚡ outbound-messageQueue
📤 Adapter SendWhatsApp API
Fluxos Paralelos
⏲ FollowupSchedulerDO com alarms
🔑 gauth JWTValidação compartilhada
🗃 R1 WorkersPostgres via Hyperdrive
⚙ Pipeline de Mensagem em Detalhes
18 etapas descritas do webhook ao envio da resposta. Clique em cada uma.
1
Webhook recebido em gchat-r3-api
POST channel-specific webhook
2
Adapter normaliza payload
ChannelAdapter.normalizeInbound
3
Enfileira em inbound-message
Cloudflare Queue
4
gagents consome (batch 20)
queue consumer
5
normalizeMessageData
Valida + anti-loop
6
MessageAggregator DO
Aggrega fragmentos
7
áudio STT (Workers AI + fallback)
Transcricao assincrona
8
Vision native OpenAI
Images urls direto ao modelo
9
Alarm DO triggers
Wait time expira
10
processMessages combina
texto + imagens + docs
11
Envia ao receive-message-normalized
próxima queue
12
Meta-agent auth check
Cross-account authorization
13
Carrega agent + system prompt
assembleStructuredPrompt
14
OpenAI Responses.create
sync, no polling
15
Tool calls loop
executeToolCalls
16
processResponse inline
sem queue intermediaria
17
Cria no_response followup
FollowupScheduler DO
18
Outbound para gchat queue
gchat-r2-outbound-message
🎞 Durable Objects — Compute com Estado
gagents usa 2 Durable Objects para problemas específicos que exigem estado persistente.
🎞

MessageAggregator

Agrega mensagens fragmentadas (WhatsApp multi-part), processa áudio/vision, gerência buffer por conversa. Arquitetura modular em 6 arquivos.

6 módulosAlarms

FollowupScheduler

Agenda followups futuros por conversa. Um DO por conversa. Usa alarms nativos do Cloudflare.

Per-conversationState storage
🧠 Integração OpenAI Responses API
gclinic usa a API mais recente da OpenAI, que substituiu a Assistants API. Clique para detalhes.
💡

Responses API

Sincrona, sem polling. Substitui threads por conversations. gpt-5.4-mini default.

📈

Context Compaction

Compactacao server-side automática a 200K tokens. Preserva histórico sem custo explosivo.

Strict Schema

Todas as tools forcam strict: true, garantindo JSON valido em toda resposta.

🔑

Prompt Hash Tracking

SHA-256 do system prompt armazenado em prompt_versions. Detecta mudanças.

🔧

Tool Execution Engine

4 executors pluggaveis: google-calendar, gagents-api, execute-skill, gclinic-internal. Com cache.

🔄

Retry Helper

3x exponential backoff (500ms base). Não retry em 400/401/403/404/422.

🔗 Comunicação entre Workers
3 formas distintas, cada uma com proposito claro.
🔗

Service Bindings

Sincrona, sem HTTP. Worker A chama Worker B diretamente. Usada entre r3-api e r1-api-postgresql.

Cloudflare Queues

Assincrona, durable. Entre gchat e gagents. Batch=20, retry=10, delay exponencial.

🌐

HTTP

Frontend → API pública. Webhooks externos (providers). Autenticado por JWT.

🔑 Fluxo de Autenticação
better-auth no cliente (sessão do browser) + gauth-r3-api no servidor (token pair). Access JWT 1h + refresh opaco 7d. Revogação via KV blacklist de jti.
1. User /loginBrowser
2. better-auth hookgclinic-r3-app
3. POST /auth/logingauth-r3-api
4. Valida PBKDF2-SHA256100k iterations
5. Emite token pairaccess JWT 1h + refresh UUID 7d
6. Session cookiebetter-auth (24h updateAge)
7. gauthToken + refreshTokenarmazenados no user
8. Bearer + KV jti blacklistrevogação via logout
9. POST /auth/refreshrotaciona pair antes de expirar
10. POST /auth/logoutrevoga refresh + blacklist jti
☁ Infraestrutura e Deploy
100% Cloudflare para os apps principais + Fly.io para o serviço Go de WhatsApp.
gclinic-r3-appNext.js 16
Cloudflare Workers
via OpenNext
gadmin-r3-appNext.js 16
Cloudflare Workers
via OpenNext
gauth/gchat/gagents r3-apiCloudflare Workers
wrangler deploy
PostgreSQLvia Hyperdrive
(proxy + pool)
Cloudflare QueuesManaged by Cloudflare
whatsmeowFly.io
Docker container
(Go 1.24)
Comandos
# Next.js apps (com Hyperdrive NAO usar 'bun run deploy')
cd gclinic/gclinic-r3-app
bun run build           # 1. Next.js build
bun run build:worker    # 2. @opennextjs/cloudflare build
bunx wrangler deploy    # 3. Deploy direto pelo wrangler

# APIs simples (r1, r3-api)
cd gauth/gauth-r3-api
bunx wrangler deploy
bunx wrangler tail      # stream logs
✨ Serviços Cloudflare em uso
Quase tudo roda na infraestrutura Cloudflare.
Workers10+ serviços (frontends, APIs, database layers)
HyperdriveProxy+pool para Postgres. Uma instancia por produto.
Queues11 filas (inbound, outbound, followups, emails, calendar sync)
Durable ObjectsMessageAggregator, FollowupScheduler
R2Fotos de pacientes, cache do Next.js, arquivos de áudio
KVCache distribuido via @greatapps/cache
Workers AITranscricao de áudio (primario)
Service BindingsComunicação interna sem HTTP entre Workers
CronsSync Calendar 5min, renovacao watches 4h
SecretsJWT_SECRET, OPENAI_API_KEY, DATABASE_URL
💡 Análise Critica — O que Eu Mudaria
Uma avaliação honesta de decisões arquiteturais do gclinic que podem causar problemas no medio prazo.
Alta

Zero contrato tipado entre frontend e APIs

gclinic-r3-app chama gauth, gchat, gagents, gclinic via fetch manual. Não ha OpenAPI, tRPC ou codegen. Cada mudança de schema e risco de quebra silenciosa em producao.

Media

whatsmeow: SPOF e estratégia de escala

Multi-sessão em processo Go único no Fly.io funciona bem para dezenas de clínicas, mas não escala linearmente. Cada sessão carrega ~30-100MB de estado crypto. Um crash derruba todas simultaneamente. Falta estratégia de sharding por session_id.

Media

R1 com endpoint único POST / que aceita JSON de operação

Perde-se tipagem de SQL em compile time. Objetos { type: 'SELECT', table, where } passam por runtime validation. Erros de schema/coluna so aparecem em producao.

Media

@greatapps/api retorna { status: 0 } em vez de throw

Falhas silenciosas são anti-pattern. Dev esquece de checar result?.status !== 1 e continua como se tivesse dado certo. Pior: update() sem match atualiza 0 linhas e retorna sucesso.

Media

Strings magicas no controle de fluxo (TOOL_ERROR, DISCARDED, etc.)

Tool outputs, meta-agent authorizations e followups usam strings para representar estado. Sem enum, sem tipos. Um typo quebra em runtime silenciosamente.

Media

5 repos independentes sem orquestracao de versão

Cada produto (gauth, gclinic, gchat, gagents, gadmin) e publicado em seu próprio repo. Localmente são agrupados em uma pasta. Não ha orquestracao de versão entre eles — deploy coordenado depende de disciplina humana.

Baixa

Coluna deleted INTEGER (0/1) em vez de boolean

Schema declara boolean mas o DB precisa ser integer. Gambiarra historica que exige treinar todo novo dev. Postgres tem BOOLEAN nativo desde sempre.

Positivo

O que esta bem feito

Apesar das criticas, ha muitas decisões excelentes. Service Bindings, Durable Objects, Responses API. Ver detalhes.