Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ Ver `.env.example` para lista completa. As principais:
| POST | `/keys` | `{"key": "k", "value": "v"}` |
| GET | `/keys/{key}` | `{"value": "v"}` |
| GET | `/stats/all` | JSON com sections: memory, wal, disk, bloom, cache |
| GET | `/scan` | Range scan com paginação cursor-based |
| GET | `/keys/search` | Prefix search com paginação |

## Frontend (Angular 17)

Expand Down Expand Up @@ -134,5 +136,30 @@ cd frontend && npm install && npm start # Angular em :4200
## Roadmap ativo

- `v2.2` — Storage iterators para range queries (em desenvolvimento)
- `v2.3` — Concurrent read optimization
- `v2.3` — Concurrent read optimization
- `v3.0` — Leveled/Tiered Compaction Strategies

---

## Comandos slash disponíveis

Use `/comando` ou `/comando argumento` na conversa:

| Comando | O que faz |
|---|---|
| `/pr` | Gera rascunho completo de Pull Request |
| `/test [filtro]` | Roda `cargo test` e interpreta resultados |
| `/review [#PR]` | Code review do diff atual ou de um PR |
| `/bench [filtro]` | Roda benchmarks Criterion e compara baseline |
| `/debug <erro>` | Diagnostica erro/panic e propõe fix |
| `/doc <arquivo>` | Gera ou completa docstrings Rust |

## Skills disponíveis

Arquivos de conhecimento especializado em `.claude/skills/`:

| Skill | Quando usar |
|---|---|
| `rust-lsm.md` | Qualquer trabalho em `src/` — convenções, fluxos, checklist |
| `api-contracts.md` | Trabalho em `src/api/` ou testes HTTP |
| `angular-frontend.md` | Qualquer trabalho em `frontend/` |
25 changes: 25 additions & 0 deletions .claude/commands/bench.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# /bench — Rodar Benchmarks

Executa benchmarks com Criterion e interpreta os resultados.

## O que fazer

1. Rode `cargo bench 2>&1 | tee /tmp/bench-out.txt`
2. Extraia para cada benchmark:
- Nome do bench
- Tempo médio (ns/µs/ms)
- Variação (lower/upper bound)
- Comparação com baseline se disponível (`change: X%`)
3. Destaque regressões (piora > 5%) em 🔴 e melhorias (> 5%) em 🟢
4. Se `$ARGUMENTS` for fornecido: `cargo bench $ARGUMENTS`

## Benchmarks disponíveis

Localização: `benches/`
- `engine_bench` — throughput de put/get na LSM Engine
- Outros listados em `Cargo.toml` sob `[[bench]]`

## Leia também

- `.claude/skills/rust-lsm.md` — contexto de performance esperada
- `.claude/memory.md` — baseline de performance registrado
24 changes: 24 additions & 0 deletions .claude/commands/debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# /debug — Diagnosticar Problema

Analisa um erro, panic ou comportamento inesperado e propõe solução.

## O que fazer

1. Leia `$ARGUMENTS` — pode ser:
- Uma mensagem de erro colada
- Um nome de arquivo/função suspeita
- Um comportamento descrito em prosa
2. Consulte `.claude/error-catalog.md` para erros conhecidos
3. Se for um erro de compilação Rust:
- Identifique o código de erro (`E0XXX`) e explique o que significa
- Mostre o trecho problemático e a correção mínima
4. Se for um erro de runtime/panic:
- Trace o caminho de execução pelo CLAUDE.md (fluxos de escrita/leitura)
- Identifique qual camada (core/storage/infra/api) está envolvida
5. Proponha fix com `diff` quando possível

## Leia também

- `.claude/error-catalog.md`
- `.claude/skills/rust-lsm.md`
- `.claude/decisions.md`
34 changes: 34 additions & 0 deletions .claude/commands/doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# /doc — Gerar Documentação

Gera ou atualiza documentação para um módulo ou função.

## O que fazer

1. Se `$ARGUMENTS` for um caminho de arquivo (`src/core/engine.rs`), documente todas as funções públicas (`pub fn`) sem `///` ou com doc incompleto
2. Se for um nome de módulo (`storage::wal`), documente o módulo inteiro
3. Padrão de doc Rust a seguir:

```rust
/// Descrição de uma linha do que a função faz.
///
/// # Arguments
/// * `key` - Descrição do argumento
///
/// # Returns
/// Descrição do retorno
///
/// # Errors
/// Lista os casos de `Err(...)` possíveis
///
/// # Example
/// ```
/// // exemplo mínimo compilável
/// ```
```

4. NÃO altere a lógica — só adicione/corrija comentários
5. Exiba o diff para aprovação antes de aplicar

## Leia também

- `.claude/skills/rust-lsm.md`
23 changes: 23 additions & 0 deletions .claude/commands/pr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# /pr — Abrir Pull Request

Gera um PR completo para a branch atual seguindo o padrão do ApexStore.

## O que fazer

1. Rode `git log main..HEAD --oneline` para listar os commits da branch
2. Rode `git diff main...HEAD --stat` para ver os arquivos alterados
3. Leia `.claude/pr-checklist.md` para aplicar o checklist
4. Monte o corpo do PR com:
- **Título**: `tipo(escopo): descrição curta` (Conventional Commits)
- **Motivação**: por que essa mudança existe
- **O que mudou**: lista dos principais arquivos/módulos
- **Como testar**: comandos `cargo test` ou `curl` para validar
- **Known limitations** se houver
- Checklist de DoD (formato checkbox)
5. Exiba o rascunho do PR para aprovação antes de criar

## Leia também

- `.claude/skills/rust-lsm.md` — convenções Rust do projeto
- `.claude/pr-checklist.md` — checklist obrigatório
- `.claude/decisions.md` — decisões de arquitetura já tomadas
33 changes: 33 additions & 0 deletions .claude/commands/review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# /review — Code Review de Diff

Faz review do diff atual ou de um PR específico.

## O que fazer

1. Se `$ARGUMENTS` for um número, revise o PR `#$ARGUMENTS` via `gh pr diff $ARGUMENTS`
2. Caso contrário, rode `git diff main...HEAD` para o diff local
3. Analise seguindo estas dimensões (ordene por severidade):

### 🔴 Bloqueadores
- `.unwrap()` / `.expect()` em código de produção (não em testes)
- Locks de leitura onde deveria haver escrow de escrita
- Paths de arquivo hardcoded
- Segredos ou credenciais no código

### 🟡 Melhorias
- Funções com mais de 50 linhas sem justificativa
- Ausência de testes para lógica nova
- Uso de `println!` em vez de `tracing::`
- Clone desnecessário de `String`/`Vec`

### 🟢 Sugestões
- Oportunidades de simplificação
- Nomes que poderiam ser mais descritivos
- Docstrings ausentes em funções públicas

4. Exiba as Issues em tabela: `| Arquivo:linha | Severidade | Descrição | Sugestão |`

## Leia também

- `.claude/skills/rust-lsm.md` — padrões do projeto
- `.claude/decisions.md` — o que NÃO mudar
29 changes: 29 additions & 0 deletions .claude/commands/test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# /test — Rodar e Analisar Testes

Executa a suite de testes do ApexStore e interpreta os resultados.

## O que fazer

1. Rode `cargo test 2>&1` e capture a saída completa
2. Separe em três grupos:
- ✅ Passou
- ❌ Falhou (mostre nome do teste + mensagem de erro)
- ⚠️ Ignorado
3. Para cada falha, leia o código-fonte do teste em `src/` ou `tests/` e explique:
- O que o teste estava verificando
- Qual foi o comportamento real vs esperado
- Sugestão de correção
4. Se `$ARGUMENTS` for fornecido, filtre os testes: `cargo test $ARGUMENTS`

## Exemplos de uso

```
/test → roda todos os testes
/test engine → roda testes com "engine" no nome
/test storage::wal → roda testes do módulo WAL
```

## Leia também

- `.claude/skills/rust-lsm.md` — contexto da engine
- `.claude/error-catalog.md` — erros conhecidos
55 changes: 55 additions & 0 deletions .claude/hooks/post-tool-lint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# PostToolUse/File: roda cargo fmt + cargo clippy no arquivo alterado.
# Faz fallback silencioso se cargo não estiver disponível.
# Usa flag de lock para evitar loop infinito de autoedição.

set -euo pipefail

LOCK_FILE="/tmp/.apexstore_lint_running"

# Anti-loop: se já estamos dentro de um ciclo de lint, sai
if [ -f "$LOCK_FILE" ]; then
exit 0
fi

INPUT=$(cat)

if command -v jq &>/dev/null; then
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""' 2>/dev/null || echo "")
else
FILE_PATH=$(echo "$INPUT" | python3 -c "
import sys, json
d = json.load(sys.stdin)
ti = d.get('tool_input', {})
print(ti.get('file_path') or ti.get('path') or '')
" 2>/dev/null || echo "")
fi

[ -z "$FILE_PATH" ] && exit 0

# Só processa arquivos Rust
if ! echo "$FILE_PATH" | grep -qE '\.rs$'; then
exit 0
fi

# Verifica se cargo está disponível
if ! command -v cargo &>/dev/null; then
echo "[AVISO] cargo não encontrado — lint ignorado. Instale rustup para habilitar gates locais." >&2
exit 0
fi

touch "$LOCK_FILE"
trap 'rm -f $LOCK_FILE' EXIT

echo "[LINT] Rodando cargo fmt em $FILE_PATH..." >&2
if ! cargo fmt -- "$FILE_PATH" 2>&1 | tail -5 >&2; then
echo "[AVISO] cargo fmt falhou em $FILE_PATH" >&2
fi

echo "[LINT] Rodando cargo clippy..." >&2
CLIPPY_OUT=$(cargo clippy --message-format=short 2>&1 | grep "$FILE_PATH" | head -10 || true)
if [ -n "$CLIPPY_OUT" ]; then
echo "[CLIPPY] $CLIPPY_OUT" >&2
fi

exit 0
57 changes: 57 additions & 0 deletions .claude/hooks/pre-tool-bash.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# PreToolUse/Bash: bloqueia comandos destrutivos ou arriscados.
# Lê o JSON do evento via stdin; extrai o campo command.

set -euo pipefail

INPUT=$(cat)

if command -v jq &>/dev/null; then
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""' 2>/dev/null || echo "")
else
CMD=$(echo "$INPUT" | python3 -c "
import sys, json
d = json.load(sys.stdin)
print(d.get('tool_input', {}).get('command') or '')
" 2>/dev/null || echo "")
fi

[ -z "$CMD" ] && exit 0

# --- Padrões destrutivos (bloqueio hard) ---
declare -A BLOCK_RULES
BLOCK_RULES['rm -rf /']= 'rm -rf na raiz do sistema é proibido.'
BLOCK_RULES['rm -rf ~']= 'rm -rf no home é proibido.'
BLOCK_RULES['git push --force']='git push --force pode destruir histórico remoto. Use --force-with-lease.'
BLOCK_RULES['git push -f']= 'git push -f pode destruir histórico remoto. Use --force-with-lease.'
BLOCK_RULES['docker system prune']='docker system prune apaga volumes/imagens sem confirmação interativa.'
BLOCK_RULES['docker volume prune']='docker volume prune apaga dados persistentes.'
BLOCK_RULES['chmod -R 777']= 'chmod -R 777 é perigoso para segurança.'
BLOCK_RULES['chmod 777']= 'chmod 777 expõe o arquivo para todos os usuários.'

for pattern in "${!BLOCK_RULES[@]}"; do
if echo "$CMD" | grep -qF "$pattern"; then
echo "[BLOQUEADO] Comando perigoso detectado." >&2
echo "Motivo: ${BLOCK_RULES[$pattern]}" >&2
echo "Comando: $CMD" >&2
exit 2
fi
done

# --- Padrões de pipe suspeito (curl|sh, wget|sh) ---
if echo "$CMD" | grep -qE '(curl|wget).+\|.*(sh|bash|zsh)'; then
echo "[BLOQUEADO] Pipe de download para shell detectado." >&2
echo "Motivo: curl/wget|sh executa código remoto sem inspeção. Baixe o script primeiro e inspecione." >&2
exit 2
fi

# --- rm -rf fora de /tmp ou target ---
if echo "$CMD" | grep -qE 'rm\s+-rf?\s+[^/]'; then
if ! echo "$CMD" | grep -qE 'rm\s+-rf?\s+(\./)?((tmp|target|/tmp|/target))'; then
echo "[AVISO] rm -rf em caminho não-temporário: $CMD" >&2
echo "Confirme se o diretório é seguro para remoção." >&2
# warning — não bloqueia
fi
fi

exit 0
66 changes: 66 additions & 0 deletions .claude/hooks/pre-tool-file.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
# PreToolUse/File: bloqueia edição de arquivos sensíveis e protegidos.
# Lê o JSON do evento via stdin; extrai o campo file_path.

set -euo pipefail

# Lê o evento completo do stdin
INPUT=$(cat)

# Extrai o caminho do arquivo (compatível com jq e com python3 como fallback)
if command -v jq &>/dev/null; then
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""' 2>/dev/null || echo "")
else
FILE_PATH=$(echo "$INPUT" | python3 -c "
import sys, json
d = json.load(sys.stdin)
ti = d.get('tool_input', {})
print(ti.get('file_path') or ti.get('path') or '')
" 2>/dev/null || echo "")
fi

[ -z "$FILE_PATH" ] && exit 0

# --- Padrões sensíveis ---
SENSITIVE_PATTERNS=(
'\.env$'
'\.env\.'
'secrets'
'\.secret'
'token'
'private_key'
'\.pem$'
'\.key$'
'\.pfx$'
'\.p12$'
'^prod'
'/prod/'
'\.git/'
)

# --- Arquivos protegidos (requerem justificativa explícita) ---
PROTECTED_PATTERNS=(
'Cargo\.lock$'
'\.github/workflows/'
'migrations/'
'docker-compose\.prod'
)

for pattern in "${SENSITIVE_PATTERNS[@]}"; do
if echo "$FILE_PATH" | grep -qE "$pattern"; then
echo "[BLOQUEADO] Arquivo sensível: $FILE_PATH" >&2
echo "Motivo: corresponde ao padrão '$pattern'. Peça permissão explícita para editar arquivos sensíveis." >&2
exit 2
fi
done

for pattern in "${PROTECTED_PATTERNS[@]}"; do
if echo "$FILE_PATH" | grep -qE "$pattern"; then
echo "[AVISO] Arquivo protegido: $FILE_PATH" >&2
echo "Motivo: '$pattern' requer justificativa clara no contexto antes de alterar." >&2
# warning apenas — não bloqueia, mas registra
exit 0
fi
done

exit 0
Loading
Loading