K
Kodama Vault
knowledge hub
Vault
HomeBoardMap of ContentChatConversasAuditoria
Agentes
AgentsIssuesTerminalPreviews
Sistema
MCPSetup MCPSettings
Brain
Global agent instructions
Análise custos migração — evitar senha no payloadLevantamento fluxo registro + duplicados StripeRelatório segurança + pentes finos (Cláudio)Revisão security concerns e race conditionsMagic link / esqueceu senha via SupabaseCorrigir erros pós-upgrade TypeScriptTestar PRs do agente Vault para mergeAnálise de 3 issues para iniciarErro no terminal do VSCodePR #173 — aguardando aprovação do LeoTestar fluxo ponta a ponta — criação de clients no StripePR #172 — testar e subir correção de funções deprecatedPitch de vendas SaaS — agendar call de conversãoOrganizar issues e bugs rápidos para a semanaMerge PR cadastro-novo — funcionalidades e correçõesCorrigir bugs PR #173 e #172 — image domainsPR mesosóico — página de acesso mobile + segurança OTPRefatoração de códigos — PR #202Ajustes em PRs abertos de ontemEstudo de jornada de compra e técnicas de fechamentoDefinir preço e entregável do produtoProspecção de reuniões para esta semanaAgente anti AI slop — centralização de conhecimento ConnfitPR #179 — resolver conflitos e erros de teste CLIAlinhamento de preços e usos da ConffitFix adicional para PR #183 — perfil do usuárioCorrigir estilização da Connfit para identidade visualSubir modificações no copy da ConnfitCriação de 4 campanhas no Meta AdsRevisão de PRs do GilinesExploração do Roblox EditorRelatório João — devolutiva TikTok ShopReunião presencial Zassi Uniformes — diagnóstico automaçõesCriar repositório de diagnósticos e relatórios de entrevistasDiagnóstico da ZassiGeração de relatórios para reuniões de fechamentoProposta Zassi — apresentação amanhãProspecção — Clínica Odontológica Dr. But
VPS Hermes — acesso e estrutura
Always Commit Push DeployHermes Voice GeminiHermes VPSKodama Prospects TrackerMEMORYObsidian VaultRoblox Mining Sim
OpenSpec -- Spec-Driven Development no VaultPlano de Teste — OpenSpec Vault Persistence
CaumzitoNyxzZanini
vek1 — arquiteturavek1 — autenticaçãovek1 — contextovek1 — regras de copy e marketingvek1 — modelo de dadosvek1 — decisões técnicasvek1 — domínio e modelo de negóciovek1 — featuresvek1 — gaps e riscosvek1 — gotchasvek1 — integrações externasvek1 — pricing design (Stripe sub + topup)vek1 — atividade recentevek1 — roteiro de vendas (SDR → fechamento)vek1 — estado e maturidadevek1 — Migração Evolution API → WhatsApp Cloud API (Meta oficial)
Claude Code — Setup MCP VaultClaude Desktop — Setup MCP Vault (remote)VS Code + Copilot — Setup MCP Vault
Skill — Carousel Designer (Paper Style)
Standup 2026-05-14Standup 2026-05-15Standup 2026-05-16Standup 2026-05-17Standup 2026-05-18Standup 2026-05-19Standup 2026-05-20Standup 2026-05-21Standup 2026-05-22Standup 2026-05-25Standup 2026-05-26Standup 2026-05-27Standup 2026-05-28Standup 2026-05-29Standup 2026-06-01Standup 2026-06-02Standup 2026-06-03Standup 2026-06-05Standup 2026-06-11Standup 2026-06-15Standup 2026-06-16Standup 2026-06-17Standups
MOCWelcome
v0.3
K
Kodama Vault
brain / projects / vek1

vek1 — autenticação

Autenticação e autorização

Stack atual: Better Auth 1.6 com HTTP adapter custom. Toda persistência de auth (user/session/account/verification) sai pra vek1-api /internal/auth/* via X-Auth-Token isolado do app token. Frontend não toca Postgres direto pra auth.

Configuração principal — src/lib/auth.ts

betterAuth({
  database: httpAdapter,                  // delega tudo pra vek1-api
  emailAndPassword: {
    enabled: true,
    autoSignIn: true,
    sendResetPassword: async ({ user, url }) => {
      await apiClient.email.sendResetPasswordEmail({
        to: user.email,
        reset_url: url,
        name: user.name,
      });
    },
    resetPasswordTokenExpiresIn: 60 * 60,
  },
  trustedOrigins: process.env.BETTER_AUTH_TRUSTED_ORIGINS?.split(',') ?? [],
  baseURL: process.env.BETTER_AUTH_URL,
  secret: process.env.BETTER_AUTH_SECRET,
})

HTTP adapter — src/lib/auth-http-adapter.ts

Implementa createAdapterFactory({...}) do Better Auth com handlers create / findOne / findMany / update / updateMany / delete / deleteMany / consumeOne / count. Responsabilidades:

  1. camelCase ↔ snake_case: Better Auth manda emailVerified, Pydantic do vek1-api exige email_verified. snakeKeys() no outgoing, camelKeys() no incoming (recursivo).
  2. Parse de timestamps: backend devolve string ISO; Better Auth precisa de Date. parseTimestampField() converte campos terminados em expiresAt|createdAt|updatedAt|...ExpiresAt.
  3. Per-model dispatcher: cada operação mapeia pra endpoint purpose-built (não CRUD genérico).
    • findOne(user, where=[{id}]) → apiClient.auth.findUserById
    • findOne(session, where=[{token}]) → apiClient.auth.findSessionByToken
    • findOne(account, where=[{providerId, accountId}]) → apiClient.auth.findAccountByProvider
    • findMany(verification, where=[{identifier|value}]) → idem (Better Auth chama findMany no reset-password)
    • consumeOne(verification, where=[{identifier, value}]) → DELETE...RETURNING atomic no vek1-api (elimina race PKCE)
  4. updateMany real: Better Auth chama updateMany no updatePassword (where=[userId, providerId='credential']). Adapter resolve TODOS os matches via findManyRows + filtro manual + updateRow em loop.

Endpoints /internal/auth/* no vek1-api

Todos exigem X-Auth-Token + Pydantic strict (extra='forbid'). Vide vek1-api/context para spec completa.

Endpoint Adapter call
POST /users create(user)
GET /users/by-id/{id} / /by-email/{email} findOne(user)
PATCH /users/{id} / DELETE /users/{id} update/delete(user)
POST /sessions create(session)
GET /sessions/by-token/{token} / /by-id/{id} findOne(session)
PATCH /sessions/{id} / DELETE /sessions/{id} update/delete(session)
DELETE /sessions/by-user/{user_id} deleteMany(session)
POST /accounts / GET /accounts/by-user/{user_id} / /by-provider?... create/findMany/findOne(account)
GET /accounts/password-by-user/{user_id} retorna hash credential pro login
POST /verifications create(verification)
GET /verifications/by-value/{value} / /by-identifier/{identifier} findOne/findMany(verification)
POST /verifications/consume consumeOne — DELETE..RETURNING atomic
DELETE /verifications/by-identifier/{identifier} bulk delete
GET /_cache-stats métrica interna (dev only)

Fluxos

Signup

  1. /register → authClient.signUp.email({ email, password, name })
  2. Better Auth chama create(user) → vek1-api POST /internal/auth/users → INSERT user
  3. Better Auth chama create(account) → INSERT account (password hash bcrypt)
  4. autoSignIn: true → create(session) → INSERT session + retorna cookie
  5. Não cria company_profiles automaticamente (sem trigger SQL como tinha no Supabase). Cliente cria manualmente em /stores ou via endpoint /internal/company/ensure.

Login

  • /login → authClient.signIn.email({ email, password })
  • Better Auth busca user por email + account com providerId='credential', compara hash, cria session

Forgot password (PR #72)

  1. /forgot-password → authClient.forgetPassword({ email, redirectTo })
  2. Better Auth: cria row em verification (identifier='reset-password:userId', value=token, expiresAt=+1h) + chama sendResetPassword
  3. sendResetPassword em auth.ts chama apiClient.email.sendResetPasswordEmail({to, reset_url, name}) → vek1-api /internal/email/send-reset-password (webhook scope) → Resend
  4. User clica no link → /reset-password?token=... → authClient.resetPassword({ newPassword, token })
  5. Better Auth: consumeOne(verification) (atomic) + updateMany(account) (atualiza hash)

OAuth callback

  • /auth/callback/route.ts ainda existe mas não é usado (sem provider OAuth configurado).

Middleware / proxy (src/proxy.ts)

Em Next 16, middleware.ts → proxy.ts. Função exportada se chama proxy, não middleware.

Whitelist de rotas públicas:

/, /login, /register, /forgot-password, /reset-password, /auth/callback

Prefixos protegidos:

/admin, /agents, /dashboard, /products, /stores, /upload, /leads, /orders, /settings,
/client-stats, /database-stats, /token-usage, /documents, /instance-settings

Rotas fora das duas listas passam livre (return NextResponse.next()).

Sem session em rota protegida → redirect /login?redirect={pathname}.

Matcher exclui api/* + assets estáticos.

Helpers SSR — src/lib/auth-server.ts

getCurrentUser(): Promise<User | null>   // lê cookie session via Better Auth
requireUser(): Promise<User>             // throw 401 se anon

Usado por Server Actions e Route Handlers pra validar antes de chamar apiClient com actorUserId: user.id.

Roles e permissões

Não há sistema de roles ainda. Modelo continua tenant = user = empresa:

better_auth.user.id == company_profiles.id == stores.company_id

Equipes/multi-usuário por company não suportados. Adicionar exigiria:

  • Tabela company_members(user_id, company_id, role)
  • Refactor todas as ownership checks no vek1-api (assert_owns_store(actor, store_id) precisa virar JOIN com membership)

Autorização granular

Sem RLS no Postgres. Autorização vive no vek1-api via dependency injection:

  • Depends(require_app_token) valida X-Internal-Token
  • actor: str = Depends(require_actor_user_id) extrai X-Actor-User-Id
  • assert_owns_store(actor, store_id), assert_owns_order(actor, order_id), assert_owns_lead(actor, lead_id), etc. — JOIN com stores.company_id

Risco: ownership check vive 100% no backend. Bug aí = exposição cross-tenant. Mitigação: cobertura de testes integration em tests/test_*_endpoints.py no vek1-api.

Envs de auth

BETTER_AUTH_SECRET                       # secret HMAC pros tokens
BETTER_AUTH_URL                          # https://vek1.vercel.app (URL canônica)
NEXT_PUBLIC_BETTER_AUTH_URL              # mesma URL pro client
BETTER_AUTH_TRUSTED_ORIGINS              # comma-separated (Vercel previews etc)

INTERNAL_AUTH_TOKEN                      # dedicado pro httpAdapter (fallback: INTERNAL_API_TOKEN)
INTERNAL_API_TOKEN                       # app scope (apiClient default)
INTERNAL_WEBHOOK_TOKEN                   # webhook scope (email, AbacatePay relay)
VEK1_API_URL                             # https://vek1-api.kodama.solutions
notas relacionadas
carregando…