mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-04 14:22:09 +03:00
docs(i18n): demonstrate translator with pt-BR backfill of CLAUDE.md + architecture/ARCHITECTURE.md
Updates docs/guides/I18N.md with a 'Translation pipeline (recommended)' section documenting the npm run i18n:run / :check / :run:dry flow, required env vars, state file semantics, and the legacy-script deprecation notice. The legacy Quick-Reference row for the Python translator is replaced with the new npm script entry. Re-translates two sources end-to-end through the new pipeline: - CLAUDE.md (1 chunk, 23k chars) - docs/architecture/ARCHITECTURE.md (14 chunks, 74k chars, one timeout retry) Both translations now have a fresh language bar regenerated from config/i18n.json (41 locales), an H1 heading with the native language tag, and prose translated into Brazilian Portuguese while preserving markdown syntax, code blocks, command names, env var identifiers, and version numbers verbatim. .i18n-state.json records the SHA-256 hash for each source and target. A second invocation with no source changes correctly reports 'work units: 0 (skipped up-to-date: 2 of 2)' and `npm run i18n:check` exits 0 — confirming the hash-based incremental + drift detection paths both work as designed. - Elapsed: ~10 min total at concurrency=4 - Cost: ~75k chars output through the configured backend Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
.i18n-state.json
Normal file
24
.i18n-state.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"sources": {
|
||||
"CLAUDE.md": {
|
||||
"source_hash": "ee7af1716a6e22feb93bb160f8b2810fa7dce8f56075b218ced51b04863f1786",
|
||||
"locales": {
|
||||
"pt-BR": {
|
||||
"source_hash": "ee7af1716a6e22feb93bb160f8b2810fa7dce8f56075b218ced51b04863f1786",
|
||||
"target_hash": "7a85c5795d376e8572598f9d963e32ec62f925b952b61b60c78fa42785836014",
|
||||
"updated_at": "2026-05-13T20:02:23.088Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs/architecture/ARCHITECTURE.md": {
|
||||
"source_hash": "573ccfe1a49d74999101460a3ee055bd07109c832d15dc9a4c6ef61ee8433302",
|
||||
"locales": {
|
||||
"pt-BR": {
|
||||
"source_hash": "573ccfe1a49d74999101460a3ee055bd07109c832d15dc9a4c6ef61ee8433302",
|
||||
"target_hash": "6daa8b7db866dd2781efd9ae02a576cf9f2cce2a8597b02a808c341e1d1335c3",
|
||||
"updated_at": "2026-05-13T20:09:25.192Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,74 @@ OmniRoute supports **30 languages** with full dashboard UI translation, translat
|
||||
|
||||
🌐 **Languages:** 🇺🇸 [English](./I18N.md) | 🇧🇷 [Português (Brasil)](./pt-BR/I18N.md) | 🇪🇸 [Español](./es/I18N.md) | 🇫🇷 [Français](./fr/I18N.md) | 🇩🇪 [Deutsch](./de/I18N.md) | 🇮🇹 [Italiano](./it/I18N.md) | 🇷🇺 [Русский](./ru/I18N.md) | 🇨🇳 [中文 (简体)](./zh-CN/I18N.md) | 🇯🇵 [日本語](./ja/I18N.md) | 🇰🇷 [한국어](./ko/I18N.md) | 🇸🇦 [العربية](./ar/I18N.md) | 🇮🇳 [हिन्दी](./hi/I18N.md) | 🇹🇭 [ไทย](./th/I18N.md) | 🇹🇷 [Türkçe](./tr/I18N.md) | 🇺🇦 [Українська](./uk-UA/I18N.md) | 🇻🇳 [Tiếng Việt](./vi/I18N.md) | 🇧🇬 [Български](./bg/I18N.md) | 🇩🇰 [Dansk](./da/I18N.md) | 🇫🇮 [Suomi](./fi/I18N.md) | 🇮🇱 [עברית](./he/I18N.md) | 🇭🇺 [Magyar](./hu/I18N.md) | 🇮🇩 [Bahasa Indonesia](./id/I18N.md) | 🇲🇾 [Bahasa Melayu](./ms/I18N.md) | 🇳🇱 [Nederlands](./nl/I18N.md) | 🇳🇴 [Norsk](./no/I18N.md) | 🇵🇹 [Português (Portugal)](./pt/I18N.md) | 🇷🇴 [Română](./ro/I18N.md) | 🇵🇱 [Polski](./pl/I18N.md) | 🇸🇰 [Slovenčina](./sk/I18N.md) | 🇸🇪 [Svenska](./sv/I18N.md) | 🇵🇭 [Filipino](./phi/I18N.md) | 🇨🇿 [Čeština](./cs/I18N.md)
|
||||
|
||||
## Translation pipeline (recommended — v3.8.0)
|
||||
|
||||
OmniRoute uses a hash-based incremental translator for docs, backed by an
|
||||
OpenAI-compatible LLM endpoint (typically `cx/gpt-5.4-mini` through OmniRoute
|
||||
Cloud):
|
||||
|
||||
```bash
|
||||
# Run translations (incremental — only touches changed sources)
|
||||
npm run i18n:run
|
||||
|
||||
# Limit to one locale
|
||||
npm run i18n:run -- --locale=pt-BR
|
||||
|
||||
# Specific files (comma-separated, repo-relative paths)
|
||||
npm run i18n:run -- --files=CLAUDE.md,docs/architecture/ARCHITECTURE.md
|
||||
|
||||
# Force retranslate everything (expensive)
|
||||
npm run i18n:run -- --force
|
||||
|
||||
# Preview what would happen (no API calls, no writes)
|
||||
npm run i18n:run:dry
|
||||
|
||||
# CI gate — exits non-zero if state is drifting
|
||||
npm run i18n:check
|
||||
```
|
||||
|
||||
**Source of truth.** `config/i18n.json` lists every locale (UI + docs) plus
|
||||
the RTL set and the `docsExcluded` codes. The runtime config in
|
||||
`src/i18n/config.ts` is a thin adapter over that JSON.
|
||||
|
||||
**Backend.** Configured via env (set in `.env`, never committed):
|
||||
|
||||
| Variable | Purpose |
|
||||
| ----------------------------------- | --------------------------------------- |
|
||||
| `OMNIROUTE_TRANSLATION_API_URL` | OpenAI-compatible base URL, e.g. `…/v1` |
|
||||
| `OMNIROUTE_TRANSLATION_API_KEY` | bearer token (kept out of logs) |
|
||||
| `OMNIROUTE_TRANSLATION_MODEL` | model id, e.g. `cx/gpt-5.4-mini` |
|
||||
| `OMNIROUTE_TRANSLATION_TIMEOUT_MS` | optional, default `60000` |
|
||||
| `OMNIROUTE_TRANSLATION_CONCURRENCY` | optional, default `4` |
|
||||
|
||||
**State tracking.** `.i18n-state.json` (committed) keeps SHA-256 hashes per
|
||||
source + per locale. Drift detection is automatic and deterministic — no API
|
||||
calls in `i18n:check`.
|
||||
|
||||
**Output shape.** Each translated file gets a top-level `# <heading>
|
||||
(<native>)` line, a `🌐 Languages: …` bar, an `---` separator, and the
|
||||
translated body. That layout matches what `scripts/check/check-docs-sync.mjs`
|
||||
already enforces for `llm.txt` and `CHANGELOG.md` mirrors.
|
||||
|
||||
### Legacy scripts (deprecated)
|
||||
|
||||
The older Python script (`scripts/i18n/i18n_autotranslate.py`) and the
|
||||
Google-Translate-backed generator (`scripts/i18n/generate-multilang.mjs`)
|
||||
still exist with a deprecation banner. They will be removed in v3.10. The
|
||||
`messages` and `readme` modes of `generate-multilang.mjs` (UI strings + root
|
||||
README variants) are not yet handled by the new pipeline and are still used.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Task | Command |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| Generate translations | `node scripts/i18n/generate-multilang.mjs messages` |
|
||||
| Translate docs (LLM) | `python3 scripts/i18n/i18n_autotranslate.py --api-url <url> --api-key <key> --model <model>` |
|
||||
| Validate a locale | `python3 scripts/i18n/validate_translation.py quick -l cs` |
|
||||
| Check code keys | `python3 scripts/i18n/check_translations.py` |
|
||||
| Generate QA report | `node scripts/i18n/generate-qa-checklist.mjs` |
|
||||
| Visual QA (Playwright) | `node scripts/i18n/run-visual-qa.mjs` |
|
||||
| Task | Command |
|
||||
| ----------------------- | ---------------------------------------------------------- |
|
||||
| Translate docs (LLM) | `npm run i18n:run` (preferred — incremental, hash-based) |
|
||||
| Translate UI strings | `node scripts/i18n/generate-multilang.mjs messages` |
|
||||
| Check translation drift | `npm run i18n:check` |
|
||||
| Validate a locale | `python3 scripts/i18n/validate_translation.py quick -l cs` |
|
||||
| Check code keys | `python3 scripts/i18n/check_translations.py` |
|
||||
| Generate QA report | `node scripts/i18n/generate-qa-checklist.mjs` |
|
||||
| Visual QA (Playwright) | `node scripts/i18n/run-visual-qa.mjs` |
|
||||
|
||||
## Architecture
|
||||
|
||||
|
||||
@@ -1,233 +1,401 @@
|
||||
# CLAUDE.md — AI Agent Session Bootstrap (Português (Brasil))
|
||||
# CLAUDE.md (Português (Brasil))
|
||||
|
||||
🌐 **Languages:** 🇺🇸 [English](../../../CLAUDE.md) · 🇸🇦 [ar](../ar/CLAUDE.md) · 🇧🇬 [bg](../bg/CLAUDE.md) · 🇧🇩 [bn](../bn/CLAUDE.md) · 🇨🇿 [cs](../cs/CLAUDE.md) · 🇩🇰 [da](../da/CLAUDE.md) · 🇩🇪 [de](../de/CLAUDE.md) · 🇪🇸 [es](../es/CLAUDE.md) · 🇮🇷 [fa](../fa/CLAUDE.md) · 🇫🇮 [fi](../fi/CLAUDE.md) · 🇫🇷 [fr](../fr/CLAUDE.md) · 🇮🇳 [gu](../gu/CLAUDE.md) · 🇮🇱 [he](../he/CLAUDE.md) · 🇮🇳 [hi](../hi/CLAUDE.md) · 🇭🇺 [hu](../hu/CLAUDE.md) · 🇮🇩 [id](../id/CLAUDE.md) · 🇮🇹 [it](../it/CLAUDE.md) · 🇯🇵 [ja](../ja/CLAUDE.md) · 🇰🇷 [ko](../ko/CLAUDE.md) · 🇮🇳 [mr](../mr/CLAUDE.md) · 🇲🇾 [ms](../ms/CLAUDE.md) · 🇳🇱 [nl](../nl/CLAUDE.md) · 🇳🇴 [no](../no/CLAUDE.md) · 🇵🇭 [phi](../phi/CLAUDE.md) · 🇵🇱 [pl](../pl/CLAUDE.md) · 🇵🇹 [pt](../pt/CLAUDE.md) · 🇧🇷 [pt-BR](../pt-BR/CLAUDE.md) · 🇷🇴 [ro](../ro/CLAUDE.md) · 🇷🇺 [ru](../ru/CLAUDE.md) · 🇸🇰 [sk](../sk/CLAUDE.md) · 🇸🇪 [sv](../sv/CLAUDE.md) · 🇰🇪 [sw](../sw/CLAUDE.md) · 🇮🇳 [ta](../ta/CLAUDE.md) · 🇮🇳 [te](../te/CLAUDE.md) · 🇹🇭 [th](../th/CLAUDE.md) · 🇹🇷 [tr](../tr/CLAUDE.md) · 🇺🇦 [uk-UA](../uk-UA/CLAUDE.md) · 🇵🇰 [ur](../ur/CLAUDE.md) · 🇻🇳 [vi](../vi/CLAUDE.md) · 🇨🇳 [zh-CN](../zh-CN/CLAUDE.md)
|
||||
🌐 **Languages:** 🇺🇸 [English](../../../CLAUDE.md) · 🇸🇦 [ar](../ar/CLAUDE.md) · 🇧🇬 [bg](../bg/CLAUDE.md) · 🇧🇩 [bn](../bn/CLAUDE.md) · 🇨🇿 [cs](../cs/CLAUDE.md) · 🇩🇰 [da](../da/CLAUDE.md) · 🇩🇪 [de](../de/CLAUDE.md) · 🇪🇸 [es](../es/CLAUDE.md) · 🇮🇷 [fa](../fa/CLAUDE.md) · 🇫🇮 [fi](../fi/CLAUDE.md) · 🇫🇷 [fr](../fr/CLAUDE.md) · 🇮🇳 [gu](../gu/CLAUDE.md) · 🇮🇱 [he](../he/CLAUDE.md) · 🇮🇳 [hi](../hi/CLAUDE.md) · 🇭🇺 [hu](../hu/CLAUDE.md) · 🇮🇩 [id](../id/CLAUDE.md) · 🇮🇩 [in](../in/CLAUDE.md) · 🇮🇹 [it](../it/CLAUDE.md) · 🇯🇵 [ja](../ja/CLAUDE.md) · 🇰🇷 [ko](../ko/CLAUDE.md) · 🇮🇳 [mr](../mr/CLAUDE.md) · 🇲🇾 [ms](../ms/CLAUDE.md) · 🇳🇱 [nl](../nl/CLAUDE.md) · 🇳🇴 [no](../no/CLAUDE.md) · 🇵🇭 [phi](../phi/CLAUDE.md) · 🇵🇱 [pl](../pl/CLAUDE.md) · 🇵🇹 [pt](../pt/CLAUDE.md) · 🇷🇴 [ro](../ro/CLAUDE.md) · 🇷🇺 [ru](../ru/CLAUDE.md) · 🇸🇰 [sk](../sk/CLAUDE.md) · 🇸🇪 [sv](../sv/CLAUDE.md) · 🇰🇪 [sw](../sw/CLAUDE.md) · 🇮🇳 [ta](../ta/CLAUDE.md) · 🇮🇳 [te](../te/CLAUDE.md) · 🇹🇭 [th](../th/CLAUDE.md) · 🇹🇷 [tr](../tr/CLAUDE.md) · 🇺🇦 [uk-UA](../uk-UA/CLAUDE.md) · 🇵🇰 [ur](../ur/CLAUDE.md) · 🇻🇳 [vi](../vi/CLAUDE.md) · 🇨🇳 [zh-CN](../zh-CN/CLAUDE.md)
|
||||
|
||||
---
|
||||
|
||||
> Quick-start context for AI coding agents. For deep architecture details, see `AGENTS.md`.
|
||||
> For contribution workflow, see `CONTRIBUTING.md`.
|
||||
Este arquivo fornece orientações para Claude Code (claude.ai/code) ao trabalhar com código neste repositório.
|
||||
|
||||
## Início Rápido
|
||||
|
||||
```bash
|
||||
npm install # Install deps (auto-generates .env from .env.example)
|
||||
npm run dev # Dev server at http://localhost:20128
|
||||
npm run build # Production build (Next.js 16 standalone)
|
||||
npm run lint # ESLint (0 errors expected; warnings are pre-existing)
|
||||
npm run typecheck:core # TypeScript check (should be clean)
|
||||
npm run typecheck:noimplicit:core # Strict check (no implicit any)
|
||||
npm run test:coverage # Unit tests + coverage gate (60% min)
|
||||
npm run check # lint + test combined
|
||||
npm run check:cycles # Detect circular dependencies
|
||||
npm install # Instalar dependências (gera automaticamente .env a partir de .env.example)
|
||||
npm run dev # Servidor de desenvolvimento em http://localhost:20128
|
||||
npm run build # Build de produção (Next.js 16 standalone)
|
||||
npm run lint # ESLint (0 erros esperados; avisos são pré-existentes)
|
||||
npm run typecheck:core # Verificação TypeScript (deve estar limpo)
|
||||
npm run typecheck:noimplicit:core # Verificação rigorosa (sem any implícito)
|
||||
npm run test:coverage # Testes unitários + gate de cobertura (75/75/75/70 — declarações/líneas/funções/branches)
|
||||
npm run check # lint + teste combinados
|
||||
npm run check:cycles # Detectar dependências circulares
|
||||
```
|
||||
|
||||
### Running a Single Test
|
||||
### Executando Testes
|
||||
|
||||
```bash
|
||||
# Node.js native test runner (most tests)
|
||||
node --import tsx/esm --test tests/unit/your-file.test.mjs
|
||||
# Arquivo de teste único (executador de teste nativo do Node.js — a maioria dos testes)
|
||||
node --import tsx/esm --test tests/unit/your-file.test.ts
|
||||
|
||||
# Vitest (MCP server, autoCombo, cache)
|
||||
# Vitest (servidor MCP, autoCombo, cache)
|
||||
npm run test:vitest
|
||||
|
||||
# Todas as suítes
|
||||
npm run test:all
|
||||
```
|
||||
|
||||
Para a matriz completa de testes, veja `CONTRIBUTING.md` → "Executando Testes". Para arquitetura profunda, veja `AGENTS.md`.
|
||||
|
||||
---
|
||||
|
||||
## Visão Geral
|
||||
## Projeto em Resumo
|
||||
|
||||
**OmniRoute** — unified AI proxy/router. One endpoint, 100+ LLM providers, auto-fallback.
|
||||
**OmniRoute** — proxy/router de IA unificado. Um endpoint, 160+ provedores de LLM, fallback automático.
|
||||
|
||||
| Layer | Location | Purpose |
|
||||
| --------------- | ------------------------ | ------------------------------------------ |
|
||||
| API Routes | `src/app/api/v1/` | Next.js App Router — entry points |
|
||||
| Handlers | `open-sse/handlers/` | Request processing (chat, embeddings, etc) |
|
||||
| Executors | `open-sse/executors/` | Provider-specific HTTP dispatch |
|
||||
| Translators | `open-sse/translator/` | Format conversion (OpenAI↔Claude↔Gemini) |
|
||||
| Services | `open-sse/services/` | Combo routing, rate limits, caching, etc |
|
||||
| Database | `src/lib/db/` | SQLite domain modules (22 files) |
|
||||
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
|
||||
| MCP Server | `open-sse/mcp-server/` | 25 tools, 3 transports, 10 scopes |
|
||||
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |
|
||||
| Skills | `src/lib/skills/` | Extensible skill framework |
|
||||
| Memory | `src/lib/memory/` | Persistent conversational memory |
|
||||
| UI Components | `src/shared/components/` | React components (Tailwind CSS v4) |
|
||||
| Provider Consts | `src/shared/constants/` | Provider registry (Zod-validated) |
|
||||
| Validation | `src/shared/validation/` | Zod v4 schemas |
|
||||
| Tests | `tests/` | Unit, integration, e2e, security, load |
|
||||
| Camada | Localização | Propósito |
|
||||
| ---------------- | ----------------------- | -------------------------------------------------------------------------------- |
|
||||
| Rotas da API | `src/app/api/v1/` | Next.js App Router — pontos de entrada |
|
||||
| Manipuladores | `open-sse/handlers/` | Processamento de requisições (chat, embeddings, etc) |
|
||||
| Executores | `open-sse/executors/` | Dispatch HTTP específico do provedor |
|
||||
| Tradutores | `open-sse/translator/` | Conversão de formato (OpenAI↔Claude↔Gemini) |
|
||||
| Transformador | `open-sse/transformer/` | API de Respostas ↔ Completações de Chat |
|
||||
| Serviços | `open-sse/services/` | Roteamento combinado, limites de taxa, cache, etc |
|
||||
| Banco de Dados | `src/lib/db/` | Módulos de domínio SQLite (45+ arquivos, 55 migrações) |
|
||||
| Domínio/Política | `src/domain/` | Motor de políticas, regras de custo, lógica de fallback |
|
||||
| Servidor MCP | `open-sse/mcp-server/` | 37 ferramentas (30 base + 3 memória + 4 habilidades), 3 transportes, ~13 escopos |
|
||||
| Servidor A2A | `src/lib/a2a/` | Protocolo de agente JSON-RPC 2.0 |
|
||||
| Habilidades | `src/lib/skills/` | Estrutura de habilidades extensível |
|
||||
| Memória | `src/lib/memory/` | Memória conversacional persistente |
|
||||
|
||||
### Monorepo Layout
|
||||
|
||||
```
|
||||
OmniRoute/ # Root package
|
||||
├── src/ # Next.js 16 app (TypeScript)
|
||||
├── open-sse/ # @omniroute/open-sse workspace (streaming engine)
|
||||
├── electron/ # Desktop app (Electron)
|
||||
├── tests/ # All test suites
|
||||
├── docs/ # Documentation
|
||||
└── bin/ # CLI entry point
|
||||
```
|
||||
Monorepo: `src/` (aplicativo Next.js 16), `open-sse/` (workspace do motor de streaming), `electron/` (aplicativo desktop), `tests/`, `bin/` (ponto de entrada CLI).
|
||||
|
||||
---
|
||||
|
||||
## Request Pipeline (Abbreviated)
|
||||
## Pipeline de Requisições
|
||||
|
||||
```
|
||||
Client → /v1/chat/completions (Next.js route)
|
||||
→ CORS → Zod validation → auth? → policy check → prompt injection guard
|
||||
Cliente → /v1/chat/completions (rota Next.js)
|
||||
→ CORS → validação Zod → auth? → verificação de política → proteção contra injeção de prompt
|
||||
→ handleChatCore() [open-sse/handlers/chatCore.ts]
|
||||
→ cache check → rate limit → combo routing?
|
||||
→ resolveComboTargets() → handleSingleModel() per target
|
||||
→ verificação de cache → limite de taxa → roteamento combinado?
|
||||
→ resolveComboTargets() → handleSingleModel() por alvo
|
||||
→ translateRequest() → getExecutor() → executor.execute()
|
||||
→ fetch() upstream → retry w/ backoff
|
||||
→ response translation → SSE stream or JSON
|
||||
→ tradução da resposta → stream SSE ou JSON
|
||||
→ Se Responses API: responsesTransformer.ts TransformStream
|
||||
```
|
||||
|
||||
As rotas da API seguem um padrão consistente: `Rota → pré-vôo CORS → validação de corpo Zod → Autenticação opcional (extractApiKey/isValidApiKey) → aplicação de política de chave da API → delegação de manipulador (open-sse)`. Sem middleware global do Next.js — a interceptação é específica da rota.
|
||||
|
||||
**Roteamento combinado** (`open-sse/services/combo.ts`): 14 estratégias (prioridade, ponderada, preenchimento-primeiro, round-robin, P2C, aleatório, menos-usado, otimizado por custo, ciente de reset, estritamente-aleatório, automático, lkgp, otimizado por contexto, retransmissão de contexto). Cada alvo chama `handleSingleModel()`, que envolve `handleChatCore()` com tratamento de erro por alvo e verificações de disjuntor. Veja `docs/routing/AUTO-COMBO.md` para a pontuação Auto-Combo de 9 fatores e `docs/architecture/RESILIENCE_GUIDE.md` para as 3 camadas de resiliência.
|
||||
|
||||
---
|
||||
|
||||
## Key Conventions
|
||||
## Estado de Execução de Resiliência
|
||||
|
||||
### Code Style
|
||||
OmniRoute possui três mecanismos de falha temporária relacionados, mas distintos. Mantenha seu
|
||||
escopo separado ao depurar o comportamento de roteamento. Veja o
|
||||
[diagrama de resiliência de 3 camadas](./docs/diagrams/exported/resilience-3layers.svg)
|
||||
(fonte: [docs/diagrams/resilience-3layers.mmd](./docs/diagrams/resilience-3layers.mmd))
|
||||
para um mapa rápido.
|
||||
|
||||
- **2 spaces**, semicolons, double quotes, 100 char width, es5 trailing commas
|
||||
- **Imports**: external → internal (`@/`, `@omniroute/open-sse`) → relative
|
||||
- **Naming**: files=camelCase/kebab, components=PascalCase, constants=UPPER_SNAKE
|
||||
### Disjuntor de Provedor
|
||||
|
||||
### Database Access
|
||||
**Escopo**: provedor inteiro, por exemplo, `glm`, `openai`, `anthropic`.
|
||||
|
||||
- **Always** go through `src/lib/db/` domain modules
|
||||
- **Never** write raw SQL in routes or handlers
|
||||
- **Never** add logic to `src/lib/localDb.ts` (re-export layer only)
|
||||
- **Never** barrel-import from `localDb.ts` — import specific `db/` modules
|
||||
- DB singleton: `getDbInstance()` from `src/lib/db/core.ts` (WAL journaling)
|
||||
- Migrations: `src/lib/db/migrations/` — 21 versioned SQL files
|
||||
**Propósito**: parar de enviar tráfego para um provedor que está falhando repetidamente no
|
||||
nível upstream/serviço, para que um provedor não saudável não atrase cada requisição.
|
||||
|
||||
### Error Handling
|
||||
**Implementação**:
|
||||
|
||||
- try/catch with specific error types, log with pino context
|
||||
- Never swallow errors in SSE streams — use abort signals
|
||||
- Return proper HTTP status codes (4xx/5xx)
|
||||
- Classe principal: `src/shared/utils/circuitBreaker.ts`
|
||||
- Fiação de gate/executação de chat: `src/sse/handlers/chatHelpers.ts`, `src/sse/handlers/chat.ts`
|
||||
- API de status em tempo de execução: `src/app/api/monitoring/health/route.ts`
|
||||
- Wrappers compartilhados: `open-sse/services/accountFallback.ts`
|
||||
- Tabela de estado persistido: `domain_circuit_breakers`
|
||||
|
||||
**Estados**:
|
||||
|
||||
- `CLOSED`: tráfego normal é permitido.
|
||||
- `OPEN`: provedor está temporariamente bloqueado; chamadores recebem uma resposta de circuito-aberto do provedor
|
||||
ou o roteamento combinado pula para outro alvo.
|
||||
- `HALF_OPEN`: o tempo limite de reset expirou; permite uma requisição de teste. Sucesso fecha o
|
||||
disjuntor, falha o abre novamente.
|
||||
|
||||
**Padrões** (`open-sse/config/constants.ts`):
|
||||
|
||||
- Provedores OAuth: limite `3`, tempo limite de reset `60s`.
|
||||
- Provedores de chave da API: limite `5`, tempo limite de reset `30s`.
|
||||
- Provedores locais: limite `2`, tempo limite de reset `15s`.
|
||||
|
||||
Somente estados de falha em nível de provedor devem acionar o disjuntor do provedor:
|
||||
|
||||
```ts
|
||||
(408, 500, 502, 503, 504);
|
||||
```
|
||||
|
||||
Não acione o disjuntor do provedor inteiro para erros normais de conta/chave/modelo como a maioria
|
||||
dos casos `401`, `403` ou `429`. Esses geralmente pertencem ao cooldown de conexão ou bloqueio de modelo. Um erro genérico de provedor de chave da API `403` deve ser recuperável, a menos que seja classificado
|
||||
como um erro terminal de provedor/conta.
|
||||
|
||||
O disjuntor usa recuperação preguiçosa, não um temporizador em segundo plano. Quando `OPEN` expira, leituras como `getStatus()`, `canExecute()`, e `getRetryAfterMs()` atualizam o estado para
|
||||
`HALF_OPEN`, para que painéis e construtores de candidatos de combinação não continuem excluindo um
|
||||
provedor expirado para sempre.
|
||||
|
||||
### Cooldown de Conexão
|
||||
|
||||
**Escopo**: uma conexão de provedor/conta/chave.
|
||||
|
||||
**Propósito**: pular temporariamente uma chave/conta ruim enquanto permite que outras conexões para
|
||||
o mesmo provedor continuem atendendo requisições.
|
||||
|
||||
**Implementação**:
|
||||
|
||||
- Caminho de escrita/atualização: `src/sse/services/auth.ts::markAccountUnavailable()`
|
||||
- Seleção/filtragem de conta: `src/sse/services/auth.ts::getProviderCredentials...`
|
||||
- Cálculo de cooldown: `open-sse/services/accountFallback.ts::checkFallbackError()`
|
||||
- Configurações: `src/lib/resilience/settings.ts`
|
||||
|
||||
Campos importantes nas conexões de provedor:
|
||||
|
||||
```ts
|
||||
rateLimitedUntil;
|
||||
testStatus: "unavailable";
|
||||
lastError;
|
||||
lastErrorType;
|
||||
errorCode;
|
||||
backoffLevel;
|
||||
```
|
||||
|
||||
Durante a seleção de conta, uma conexão é pulada enquanto:
|
||||
|
||||
```ts
|
||||
new Date(rateLimitedUntil).getTime() > Date.now();
|
||||
```
|
||||
|
||||
Cooldowns também são preguiçosos: quando `rateLimitedUntil` está no passado, a conexão se torna
|
||||
elegível novamente. Ao usar com sucesso, `clearAccountError()` limpa `testStatus`,
|
||||
`rateLimitedUntil`, campos de erro e `backoffLevel`.
|
||||
|
||||
Comportamento padrão de cooldown de conexão:
|
||||
|
||||
- Cooldown base de OAuth: `5s`.
|
||||
- Cooldown base de chave da API: `3s`.
|
||||
- Chave da API `429` deve preferir dicas de retry upstream (`Retry-After`, cabeçalhos de reset, ou
|
||||
texto de reset analisável) quando disponíveis.
|
||||
- Falhas recuperáveis repetidas usam backoff exponencial:
|
||||
|
||||
```ts
|
||||
baseCooldownMs * 2 ** failureIndex;
|
||||
```
|
||||
|
||||
O guardião anti-thundering-herd impede que falhas concorrentes na mesma conexão
|
||||
estendam repetidamente o cooldown ou dobrem o incremento de `backoffLevel`.
|
||||
|
||||
Estados terminais não são cooldowns. `banned`, `expired`, e `credits_exhausted` são
|
||||
destinados a permanecer indisponíveis até que credenciais/configurações mudem ou um operador os redefina.
|
||||
Não sobrescreva estados terminais com estado de cooldown transitório.
|
||||
|
||||
### Bloqueio de Modelo
|
||||
|
||||
**Escopo**: provedor + conexão + modelo.
|
||||
|
||||
**Propósito**: evitar desabilitar uma conexão inteira quando apenas um modelo está indisponível ou
|
||||
com limite de cota para essa conexão.
|
||||
|
||||
Exemplos:
|
||||
|
||||
- Provedores de cota por modelo retornando `429`.
|
||||
- Provedores locais retornando `404` para um modelo ausente.
|
||||
- Falhas de permissão de modo/modelo específicas do provedor, como modos Grok selecionados.
|
||||
|
||||
O bloqueio de modelo vive em `open-sse/services/accountFallback.ts` e permite que a mesma
|
||||
conexão continue atendendo outros modelos.
|
||||
|
||||
### Orientações para Depuração
|
||||
|
||||
- Se todas as chaves para um provedor forem puladas, inspecione tanto o estado do disjuntor do provedor quanto o `rateLimitedUntil`/`testStatus` de cada conexão.
|
||||
- Se um provedor parecer permanentemente excluído após a janela de reset, verifique se o código
|
||||
está lendo o `state` bruto em vez de usar `getStatus()`/`canExecute()`.
|
||||
- Se uma chave de provedor falhar, mas outras devem funcionar, prefira o cooldown de conexão em vez
|
||||
do disjuntor do provedor.
|
||||
- Se apenas um modelo falhar, prefira o bloqueio de modelo em vez do cooldown de conexão.
|
||||
- Se um estado deve se recuperar automaticamente, ele deve ter um timestamp futuro/tempo limite de reset e um
|
||||
caminho de leitura que atualiza o estado expirado. Status permanentes requerem mudanças manuais de credenciais
|
||||
ou configuração.
|
||||
|
||||
## Convenções Chave
|
||||
|
||||
### Estilo de Código
|
||||
|
||||
- **2 espaços**, ponto e vírgula, aspas duplas, largura de 100 caracteres, vírgulas finais ES5 (aplicadas pelo lint-staged via Prettier)
|
||||
- **Imports**: externo → interno (`@/`, `@omniroute/open-sse`) → relativo
|
||||
- **Nomeação**: arquivos=camelCase/kebab, componentes=PascalCase, constantes=UPPER_SNAKE
|
||||
- **ESLint**: `no-eval`, `no-implied-eval`, `no-new-func` = erro em todo lugar; `no-explicit-any` = aviso em `open-sse/` e `tests/`
|
||||
- **TypeScript**: `strict: false`, alvo ES2022, módulo esnext, resolução bundler. Preferir tipos explícitos.
|
||||
|
||||
### Banco de Dados
|
||||
|
||||
- **Sempre** passe pelos módulos de domínio em `src/lib/db/` — **nunca** escreva SQL bruto em rotas ou manipuladores
|
||||
- **Nunca** adicione lógica em `src/lib/localDb.ts` (apenas camada de re-exportação)
|
||||
- **Nunca** faça importação em lote de `localDb.ts` — importe módulos específicos de `db/` em vez disso
|
||||
- Singleton de DB: `getDbInstance()` de `src/lib/db/core.ts` (journaling WAL)
|
||||
- Migrações: `src/lib/db/migrations/` — arquivos SQL versionados, idempotentes, executados em transações
|
||||
|
||||
### Tratamento de Erros
|
||||
|
||||
- try/catch com tipos de erro específicos, registre com contexto pino
|
||||
- Nunca oculte erros em streams SSE — use sinais de abortar para limpeza
|
||||
- Retorne códigos de status HTTP apropriados (4xx/5xx)
|
||||
|
||||
### Segurança
|
||||
|
||||
- **Never** commit secrets/credentials
|
||||
- **Never** use `eval()`, `new Function()`, or implied eval
|
||||
- Validate all inputs with Zod schemas
|
||||
- Encrypt credentials at rest (AES-256-GCM)
|
||||
- **Nunca** use `eval()`, `new Function()`, ou eval implícito
|
||||
- Valide todas as entradas com esquemas Zod
|
||||
- Criptografe credenciais em repouso (AES-256-GCM)
|
||||
- Lista de negação de cabeçalhos upstream: `src/shared/constants/upstreamHeaders.ts` — mantenha a sanitização, esquemas Zod e testes unitários alinhados ao editar
|
||||
|
||||
---
|
||||
|
||||
## Common Modification Scenarios
|
||||
## Cenários Comuns de Modificação
|
||||
|
||||
### Adding a New Provider
|
||||
### Adicionando um Novo Provedor
|
||||
|
||||
1. Register in `src/shared/constants/providers.ts` (Zod-validated at load)
|
||||
2. Add executor in `open-sse/executors/` if custom logic needed
|
||||
3. Add translator in `open-sse/translator/` if non-OpenAI format
|
||||
4. Add OAuth config in `src/lib/oauth/constants/oauth.ts` if OAuth-based
|
||||
5. Register models in `open-sse/config/providerRegistry.ts`
|
||||
6. Write tests in `tests/unit/` (registration, translation, error handling)
|
||||
1. Registre em `src/shared/constants/providers.ts` (validado por Zod ao carregar)
|
||||
2. Adicione executor em `open-sse/executors/` se lógica personalizada for necessária (estenda `BaseExecutor`)
|
||||
3. Adicione tradutor em `open-sse/translator/` se formato não for OpenAI
|
||||
4. Adicione configuração OAuth em `src/lib/oauth/constants/oauth.ts` se baseado em OAuth
|
||||
5. Registre modelos em `open-sse/config/providerRegistry.ts`
|
||||
6. Escreva testes em `tests/unit/`
|
||||
|
||||
### Adding a New API Route
|
||||
### Adicionando uma Nova Rota de API
|
||||
|
||||
1. Create directory under `src/app/api/v1/your-route/`
|
||||
2. Create `route.ts` with `GET`/`POST` handlers
|
||||
3. Follow pattern: CORS → Zod body validation → optional auth → handler delegation
|
||||
4. Handler goes in `open-sse/handlers/` (import from there, not inline)
|
||||
5. Add tests
|
||||
1. Crie diretório em `src/app/api/v1/sua-rota/`
|
||||
2. Crie `route.ts` com manipuladores `GET`/`POST`
|
||||
3. Siga o padrão: CORS → validação do corpo Zod → autenticação opcional → delegação de manipulador
|
||||
4. O manipulador vai em `open-sse/handlers/` (importe de lá, não inline)
|
||||
5. Adicione testes
|
||||
|
||||
### Adding a New DB Module
|
||||
### Adicionando um Novo Módulo de DB
|
||||
|
||||
1. Create `src/lib/db/yourModule.ts`
|
||||
2. Import `getDbInstance` from `./core.ts`
|
||||
3. Export CRUD functions for your domain table(s)
|
||||
4. Add migration in `src/lib/db/migrations/` if new tables needed
|
||||
5. Re-export from `src/lib/localDb.ts` (add to the re-export list only)
|
||||
6. Write tests
|
||||
1. Crie `src/lib/db/seuModulo.ts` — importe `getDbInstance` de `./core.ts`
|
||||
2. Exporte funções CRUD para sua(s) tabela(s) de domínio
|
||||
3. Adicione migração em `src/lib/db/migrations/` se novas tabelas forem necessárias
|
||||
4. Re-exporte de `src/lib/localDb.ts` (adicione apenas à lista de re-exportação)
|
||||
5. Escreva testes
|
||||
|
||||
### Adding a New MCP Tool
|
||||
### Adicionando uma Nova Ferramenta MCP
|
||||
|
||||
1. Add tool definition in `open-sse/mcp-server/tools/`
|
||||
2. Define Zod input schema + async handler
|
||||
3. Register in tool set (wired by `createMcpServer()`)
|
||||
4. Assign to appropriate scope(s)
|
||||
5. Write tests (tool invocation logged to `mcp_audit` table)
|
||||
1. Adicione definição da ferramenta em `open-sse/mcp-server/tools/` com esquema de entrada Zod + manipulador assíncrono
|
||||
2. Registre no conjunto de ferramentas (conectado por `createMcpServer()`)
|
||||
3. Atribua aos escopos apropriados
|
||||
4. Escreva testes (invocação da ferramenta registrada na tabela `mcp_audit`)
|
||||
|
||||
### Adding a New A2A Skill
|
||||
### Adicionando uma Nova Habilidade A2A
|
||||
|
||||
1. Create skill in `src/lib/a2a/skills/`
|
||||
2. Skill receives task context (messages, metadata) → returns structured result
|
||||
3. Register in the DB-backed skill registry
|
||||
4. Write tests
|
||||
1. Crie habilidade em `src/lib/a2a/skills/` (5 já existem: smart-routing, quota-management, provider-discovery, cost-analysis, health-report)
|
||||
2. A habilidade recebe contexto de tarefa (mensagens, metadados) → retorna resultado estruturado
|
||||
3. Registre em `A2A_SKILL_HANDLERS` em `src/lib/a2a/taskExecution.ts`
|
||||
4. Exponha em `src/app/.well-known/agent.json/route.ts` (Cartão do Agente)
|
||||
5. Escreva testes em `tests/unit/`
|
||||
6. Documente na tabela de habilidades em `docs/frameworks/A2A-SERVER.md`
|
||||
|
||||
### Adicionando um Novo Agente de Nuvem
|
||||
|
||||
1. Crie classe de agente em `src/lib/cloudAgent/agents/` estendendo `CloudAgentBase` (3 já existem: codex-cloud, devin, jules)
|
||||
2. Implemente `createTask`, `getStatus`, `approvePlan`, `sendMessage`, `listSources`
|
||||
3. Registre em `src/lib/cloudAgent/registry.ts`
|
||||
4. Adicione tratamento de OAuth/credenciais se necessário (`src/lib/oauth/providers/`)
|
||||
5. Testes + documente em `docs/frameworks/CLOUD_AGENT.md`
|
||||
|
||||
### Adicionando um Novo Guardrail / Eval / Habilidade / Evento de Webhook
|
||||
|
||||
- Guardrail: `src/lib/guardrails/` → docs: `docs/security/GUARDRAILS.md`
|
||||
- Conjunto de Eval: `src/lib/evals/` → docs: `docs/frameworks/EVALS.md`
|
||||
- Habilidade (sandbox): `src/lib/skills/` → docs: `docs/frameworks/SKILLS.md`
|
||||
- Evento de Webhook: `src/lib/webhookDispatcher.ts` → docs: `docs/frameworks/WEBHOOKS.md`
|
||||
|
||||
## Documentação de Referência
|
||||
|
||||
Para qualquer alteração não trivial, leia primeiro a análise correspondente:
|
||||
|
||||
| Área | Documento |
|
||||
| --------------------------------------------------- | ----------------------------------------------------------------- |
|
||||
| Navegação no repositório | `docs/architecture/REPOSITORY_MAP.md` |
|
||||
| Arquitetura | `docs/architecture/ARCHITECTURE.md` |
|
||||
| Referência de engenharia | `docs/architecture/CODEBASE_DOCUMENTATION.md` |
|
||||
| Auto-Combo (pontuação de 9 fatores, 14 estratégias) | `docs/routing/AUTO-COMBO.md` |
|
||||
| Resiliência (3 mecanismos) | `docs/architecture/RESILIENCE_GUIDE.md` |
|
||||
| Repetição de raciocínio | `docs/routing/REASONING_REPLAY.md` |
|
||||
| Estrutura de habilidades | `docs/frameworks/SKILLS.md` |
|
||||
| Sistema de memória (FTS5 + Qdrant) | `docs/frameworks/MEMORY.md` |
|
||||
| Agentes de nuvem | `docs/frameworks/CLOUD_AGENT.md` |
|
||||
| Guardrails (PII / injeção / visão) | `docs/security/GUARDRAILS.md` |
|
||||
| Avaliações | `docs/frameworks/EVALS.md` |
|
||||
| Conformidade / auditoria | `docs/security/COMPLIANCE.md` |
|
||||
| Webhooks | `docs/frameworks/WEBHOOKS.md` |
|
||||
| Pipeline de autorização | `docs/architecture/AUTHZ_GUIDE.md` |
|
||||
| Stealth (TLS / impressão digital) | `docs/security/STEALTH_GUIDE.md` |
|
||||
| Protocolos de agente (A2A / ACP / Nuvem) | `docs/frameworks/AGENT_PROTOCOLS_GUIDE.md` |
|
||||
| Servidor MCP | `docs/frameworks/MCP-SERVER.md` |
|
||||
| Servidor A2A | `docs/frameworks/A2A-SERVER.md` |
|
||||
| Referência de API + OpenAPI | `docs/reference/API_REFERENCE.md` + `docs/reference/openapi.yaml` |
|
||||
| Catálogo de provedores (gerado automaticamente) | `docs/reference/PROVIDER_REFERENCE.md` |
|
||||
| Fluxo de lançamento | `docs/ops/RELEASE_CHECKLIST.md` |
|
||||
|
||||
---
|
||||
|
||||
## Testing Cheat Sheet
|
||||
## Testes
|
||||
|
||||
| What | Command |
|
||||
| ----------------------- | ------------------------------------------------------- |
|
||||
| All tests | `npm run test:all` |
|
||||
| Unit tests | `npm run test:unit` |
|
||||
| Single file | `node --import tsx/esm --test tests/unit/file.test.mjs` |
|
||||
| Vitest (MCP, autoCombo) | `npm run test:vitest` |
|
||||
| E2E (Playwright) | `npm run test:e2e` |
|
||||
| Protocol E2E (MCP+A2A) | `npm run test:protocols:e2e` |
|
||||
| Ecosystem | `npm run test:ecosystem` |
|
||||
| Coverage gate | `npm run test:coverage` (60% min all metrics) |
|
||||
| Coverage report | `npm run coverage:report` |
|
||||
| O que | Comando |
|
||||
| ----------------------- | ------------------------------------------------------------------------------- |
|
||||
| Testes unitários | `npm run test:unit` |
|
||||
| Arquivo único | `node --import tsx/esm --test tests/unit/file.test.ts` |
|
||||
| Vitest (MCP, autoCombo) | `npm run test:vitest` |
|
||||
| E2E (Playwright) | `npm run test:e2e` |
|
||||
| Protocolo E2E (MCP+A2A) | `npm run test:protocols:e2e` |
|
||||
| Ecossistema | `npm run test:ecosystem` |
|
||||
| Portão de cobertura | `npm run test:coverage` (75/75/75/70 — declarações/líneas/funções/ramificações) |
|
||||
| Relatório de cobertura | `npm run coverage:report` |
|
||||
|
||||
**PR rule**: If you change production code in `src/`, `open-sse/`, `electron/`, or `bin/`,
|
||||
you must include or update tests in the same PR.
|
||||
**Regra de PR**: Se você alterar o código de produção em `src/`, `open-sse/`, `electron/` ou `bin/`, você deve incluir ou atualizar testes no mesmo PR.
|
||||
|
||||
**Test layer preference**: unit first → integration (multi-module or DB state) → e2e (UI/workflow only). Encode bug reproductions as automated tests before or alongside the fix.
|
||||
**Preferência de camada de teste**: unitário primeiro → integração (multi-módulo ou estado do DB) → e2e (somente UI/workflow). Codifique reproduções de bugs como testes automatizados antes ou junto com a correção.
|
||||
|
||||
**Política de cobertura do Copilot**: Quando um PR altera o código de produção e a cobertura está abaixo de 75% (declarações/líneas/funções) ou 70% (ramificações), não apenas relate — adicione ou atualize testes, reexecute o portão de cobertura e, em seguida, peça confirmação. Inclua comandos executados, arquivos de teste alterados e o resultado final da cobertura no relatório do PR.
|
||||
|
||||
---
|
||||
|
||||
## Git Workflow
|
||||
## Fluxo de Trabalho do Git
|
||||
|
||||
```bash
|
||||
# Never commit directly to main
|
||||
git checkout -b feat/your-feature
|
||||
# ... make changes ...
|
||||
git commit -m "feat: describe your change"
|
||||
git push -u origin feat/your-feature
|
||||
# Nunca faça commit diretamente no main
|
||||
git checkout -b feat/sua-funcionalidade
|
||||
git commit -m "feat: descreva sua alteração"
|
||||
git push -u origin feat/sua-funcionalidade
|
||||
```
|
||||
|
||||
**Branch prefixes**: `feat/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`
|
||||
**Prefixos de branch**: `feat/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`
|
||||
|
||||
**Commit format** ([Conventional Commits](https://www.conventionalcommits.org/)):
|
||||
**Formato de commit** (Commits Convencionais): `feat(db): adicionar circuito de interrupção` — escopos: `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`, `mcp`, `a2a`, `memory`, `skills`
|
||||
|
||||
```
|
||||
feat: add circuit breaker for provider calls
|
||||
fix: resolve JWT secret validation edge case
|
||||
docs: update AGENTS.md with pipeline internals
|
||||
test: add MCP tool unit tests
|
||||
refactor(db): consolidate rate limit tables
|
||||
```
|
||||
**Ganchos do Husky**:
|
||||
|
||||
**Scopes**: `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`, `mcp`, `a2a`,
|
||||
`memory`, `skills`.
|
||||
- **pre-commit**: lint-staged + `check-docs-sync` + `check:any-budget:t11`
|
||||
- **pre-push**: `npm run test:unit`
|
||||
|
||||
---
|
||||
|
||||
## Environment
|
||||
## Ambiente
|
||||
|
||||
- **Runtime**: Node.js ≥18 <24, ES Modules
|
||||
- **TypeScript**: 5.9, target ES2022, module esnext, resolution bundler
|
||||
- **Path aliases**: `@/*` → `src/`, `@omniroute/open-sse` → `open-sse/`
|
||||
- **Default port**: 20128 (API + dashboard on same port)
|
||||
- **Data directory**: `DATA_DIR` env var, defaults to `~/.omniroute/`
|
||||
- **Key env vars**: `PORT`, `JWT_SECRET`, `INITIAL_PASSWORD`, `REQUIRE_API_KEY`, `APP_LOG_LEVEL`
|
||||
- **Tempo de Execução**: Node.js ≥20.20.2 <21 || ≥22.22.2 <23 || ≥24 <25, Módulos ES
|
||||
- **TypeScript**: 5.9+, alvo ES2022, módulo esnext, resolução bundler
|
||||
- **Aliases de caminho**: `@/*` → `src/`, `@omniroute/open-sse` → `open-sse/`, `@omniroute/open-sse/*` → `open-sse/*`
|
||||
- **Porta padrão**: 20128 (API + dashboard na mesma porta)
|
||||
- **Diretório de dados**: variável de ambiente `DATA_DIR`, padrão para `~/.omniroute/`
|
||||
- **Principais variáveis de ambiente**: `PORT`, `JWT_SECRET`, `API_KEY_SECRET`, `INITIAL_PASSWORD`, `REQUIRE_API_KEY`, `APP_LOG_LEVEL`
|
||||
- Configuração: `cp .env.example .env` e então gere `JWT_SECRET` (`openssl rand -base64 48`) e `API_KEY_SECRET` (`openssl rand -hex 32`)
|
||||
|
||||
---
|
||||
|
||||
## Hard Rules (Never Violate)
|
||||
## Regras Estritas
|
||||
|
||||
1. Never commit secrets or credentials
|
||||
2. Never add logic to `localDb.ts`
|
||||
3. Never use `eval()` / `new Function()` / implied eval
|
||||
4. Never commit directly to `main`
|
||||
5. Never write raw SQL in routes — use `src/lib/db/` modules
|
||||
6. Never silently swallow errors in SSE streams
|
||||
7. Always validate inputs with Zod schemas
|
||||
8. Always include tests when changing production code
|
||||
9. Coverage must stay ≥60% (statements, lines, functions, branches)
|
||||
1. Nunca faça commit de segredos ou credenciais
|
||||
2. Nunca adicione lógica ao `localDb.ts`
|
||||
3. Nunca use `eval()` / `new Function()` / eval implícito
|
||||
4. Nunca faça commit diretamente no `main`
|
||||
5. Nunca escreva SQL bruto em rotas — use módulos `src/lib/db/`
|
||||
6. Nunca silenciosamente ignore erros em streams SSE
|
||||
7. Sempre valide entradas com esquemas Zod
|
||||
8. Sempre inclua testes ao alterar código de produção
|
||||
9. A cobertura deve permanecer ≥75% (declarações, linhas, funções) / ≥70% (ramificações). Medido atualmente: ~82%.
|
||||
10. Nunca contorne ganchos do Husky (`--no-verify`, `--no-gpg-sign`) sem aprovação explícita do operador.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user