Pular para o conteúdo

Stack Técnico

Arquitetura central: Domain Kernel em TypeScript puro + Emmett como event-sourcing kernel + raw para todo o resto (ADR-001). Ver Domain Kernel.

Primary surface (ADR-002): MCP Server + MCP Apps + Open WebUI sidecar OBRIGATÓRIO. Sem admin Next.js até pós-v1.0. Ver Interfaces e ADR-002.

TecnologiaPapel
TypeScript (strict)packages/domain — funções puras decide / evolve
Emmett (event-driven-io)Event store (in-memory + Postgres), command handler, optimistic concurrency, test harness
VitestTestes GIVEN/WHEN/THEN, scenario coverage, watch mode
ULID (ulid npm)IDs lexicograficamente ordenáveis para eventos e aggregates

Primary Surface — MCP Server + MCP Apps + Open WebUI (ADR-002)

Seção intitulada “Primary Surface — MCP Server + MCP Apps + Open WebUI (ADR-002)”

Sem admin Next.js standalone. Toda interação humana via Open WebUI + MCP Apps inline. REST apps/api cobre Nível-4 critical commands + integrações. Ver Interfaces.

TecnologiaPapel
MCP Server (@modelcontextprotocol/sdk)Exposição de Tools (commands) + Resources (read models) + Apps (UI inline) — consumido por Claude / ChatGPT / Open WebUI
MCP Apps (ext-apps)Componentes UI interativos renderizados dentro do chat — substituem 80+ telas CRUD de ERP tradicional. v0.2.1: MemberQuotaCardApp, TraceabilityTimelineApp, DispensationFormApp. v0.3+: InventoryLotPickerApp, MemberSearchApp, SngpcPendingApp, KpiDashboardApp, BspoReviewApp, RipdReviewApp, LgpdRequestsApp, AuditTimelineApp
packages/ui-apps/Pacote canônico — manifests + HTML bundles (single-file via vite-plugin-singlefile). Registry em src/registry.ts.
OAuth 2.1 (per MCP spec)Autorização agente↔canna-oss; agente age em nome de usuário humano com escopo limitado
OpenAPI auto-geradoPara hosts OpenAPI-only (Open WebUI Tools, integradores tradicionais)
mcpo bridgeMCP-to-OpenAPI proxy quando host não fala MCP nativo
Open WebUI v0.9.6+ (sidecar OBRIGATÓRIO)Chat host primário — ghcr.io/open-webui/open-webui:v0.9.6 em docker-compose. MCP server registrado via config file. OAuth 2.1 mapeando scopes para canna roles. Workspace Tools desabilitado (ENABLE_KB_EXEC=false).
TecnologiaPapel
Fastify 5HTTP server fino — chama app-services, sem regra de negócio
Drizzle ORMApenas read models — schema explícito, SQL legível. Event store é Emmett, não Drizzle.
ZodValidação de schema HTTP em runtime
BullMQSide effects assíncronos (PDFs, SNGPC, BSPO)
RedisBullMQ broker + cache de read model
TecnologiaPapel
PostgreSQL 16Banco principal com pgAudit
pgAuditLog de auditoria imutável por evento SQL
Redis 7Cache de sessão + filas
BullMQWorker de jobs assíncronos
TecnologiaPapel
MinIOS3-compatible self-hosted (laudos, docs)
Puppeteer headlessGeração de PDFs (relatórios, carteirinhas)
TecnologiaPapel
JWT (jose)Tokens de sessão stateless
TOTP (speakeasy)2FA nativo sem SaaS

Não há dependência de Auth0, Clerk, Supabase Auth ou qualquer SaaS externo. Dados de membro permanecem no servidor da associação.

TecnologiaPapel
Kamal 2Deploy zero-downtime via Docker
Docker + ComposeContainerização local e CI
CaddyReverse proxy + TLS automático (Let’s Encrypt)
Hetzner DEVPS GDPR-aligned (Frankfurt)
Restic + S3Backup cifrado incremental
Grafana + PrometheusObservabilidade interna

LGPD Art. 5 II — dados de saúde como dados sensíveis:

Prescrições médicas, condições tratadas, histórico de dispensação e documentos médicos dos membros são dados sensíveis na definição da LGPD. Armazená-los em SaaS multi-tenant (Supabase, PlanetScale, AWS RDS SaaS) cria risco jurídico direto para a diretoria da associação:

  • Necessidade de RIPD (Relatório de Impacto à Proteção de Dados)
  • Contrato de processamento com cada sub-processador
  • Transferência internacional (maioria dos SaaS) requer BCRs ou cláusulas padrão ANPD
  • Responsabilidade solidária da diretoria em caso de vazamento

Self-hosted elimina todos esses vetores: dados ficam no servidor da associação, sob controle exclusivo do DPO nomeado.


Hetzner CX22 DE (€5.92/mês) + Kamal 2 + Caddy TLS auto
  • VPS Frankfurt, GDPR-aligned
  • TLS automático via Let’s Encrypt
  • Deploy zero-downtime com kamal deploy
  • Backup Restic → Hetzner Object Storage (Frankfurt)
  • Custo total: ~€15–25/mês (VPS + storage + snapshot)
Intel NUC ou Raspberry Pi 5 + Docker + Tailscale funnel
  • Hardware próprio da associação (sem pagamento mensal)
  • Zero porta aberta na internet — acesso exclusivo via Tailscale
  • Ideal para associações com TI interno
  • Risco: dependência do hardware físico (requer backup Restic externo)
Schema isolation por associação + plano managed (canna-oss cloud)
  • Modelo de negócio SaaS gerenciado pelo canna-oss
  • Infraestrutura compartilhada com isolamento por schema PostgreSQL
  • Contratos de processamento pré-negociados (DPA padrão LGPD)
  • Ver: Revenue Model

Associações operam em zona cinzenta regulatória. O sistema é projetado para não chamar atenção:

PrincípioImplementação
URLs neutras/app.associacao.com.br — sem “cannabis” na URL
PWA sem app storeInstalação direta via browser, sem Apple/Google review
Zero telemetria terceirosSem Google Analytics, Meta Pixel, Hotjar
White-label por associaçãoNome, logo e cores customizáveis por tenant
Nenhum cookie de rastreamentoSessão JWT only, sem third-party cookies
Domínio próprioCada associação usa seu próprio domínio/subdomínio

O sistema não coleta nem transmite dados para nenhum servidor externo fora do controle da associação.