Skip to content

feat: v6 — optional PostgreSQL backend for horizontal scale (tested vs Postgres 16)#65

Merged
danzeroum merged 1 commit into
masterfrom
claude/adoring-curie-wknuzy
Jun 21, 2026
Merged

feat: v6 — optional PostgreSQL backend for horizontal scale (tested vs Postgres 16)#65
danzeroum merged 1 commit into
masterfrom
claude/adoring-curie-wknuzy

Conversation

@danzeroum

Copy link
Copy Markdown
Owner

Resumo

v6 (decisão do dono: "Backend PostgreSQL agora"). Adiciona um backend PostgreSQL opcional para o estado cross-process, habilitando escala horizontal real (múltiplos hosts/réplicas escrevendo estado). SQLite continua o padrão e o caminho 100% testado. Tracker: docs/roadmap_v6.md.

O que muda

  • src/core/db.py dual-backend: DATABASE_URL=postgresql://… troca toda a camada para Postgres. Um shim fino mantém todos os call sites inalterados: placeholders ?%s, rows híbridas (row[0] e row["col"], dict(row)), upsert() (INSERT OR REPLACE/IGNOREON CONFLICT), autoincrement_pk().
  • Migrations Postgres (migrations/postgres/, BIGSERIAL + default to_char); init_db escolhe o diretório por backend.
  • journal usa RETURNING id no PG (sem lastrowid); ledger / position_store / registry / orders verificados nos dois backends.
  • psycopg[binary] (lazy import; só usado quando DATABASE_URL é PG) + serviço postgres no compose sob o perfil scale.

Testado de verdade

  • Teste de integração real contra Postgres 16 (tests/integration/test_postgres_backend.py, 8 testes): migrations, rows híbridas, ledger, position store (upsert/replace/delete), circuit state, registry, ordens (INSERT+UPDATE), journal RETURNING. Pulado quando não há DATABASE_URL (ex.: CI).
  • SQLite inalterado: 406 passed, 8 skipped, cobertura 72.51% (gate 72), ruff limpo, compose válido.
  • Linhas exclusivas de PG marcadas # pragma: no cover (cobertas pelo teste gated) → gate honesto para o núcleo SQLite.

Como ativar

DATABASE_URL=postgresql://ct:ct@postgres:5432/criptotrade docker compose --profile scale up -d

Resta (gated por ADR-005)

Leader election do loop (HA com réplica redundante) — quando "zero downtime" for requisito. Ver docs/pendencia.v2.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_014htKJbgi3z1m3kzDVwXwfS


Generated by Claude Code

Roadmap v6 (owner decision: "Postgres now"). Adds an OPTIONAL Postgres backend
for the cross-process state; SQLite stays the default and the fully-tested path.

- Dual-backend src/core/db.py: DATABASE_URL=postgresql://... switches the whole
  layer to Postgres. A thin compatibility shim keeps every call site unchanged:
  ? -> %s placeholders, hybrid rows (row[0] AND row["col"], dict(row)),
  upsert() (INSERT OR REPLACE/IGNORE <-> ON CONFLICT), autoincrement_pk().
- Postgres migrations (migrations/postgres/, BIGSERIAL + to_char default);
  init_db picks the dir by backend.
- journal uses RETURNING id on Postgres (no lastrowid); ledger/position_store/
  registry/orders verified on both backends.
- psycopg[binary] dependency (lazy-imported; only used when DATABASE_URL is PG)
  + postgres service in docker-compose under the `scale` profile.
- Real integration test (tests/integration/test_postgres_backend.py, 8 tests)
  run against Postgres 16 — skipped when DATABASE_URL is unset (e.g. CI).
  PG-only lines marked pragma:no-cover (covered by that gated test).

SQLite suite unchanged: 406 passed, 8 skipped, coverage 72.51% (gate 72), ruff
clean, compose validates. Docs: ADR-005, README, docs/roadmap_v6.md, pendencia.v2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014htKJbgi3z1m3kzDVwXwfS
@danzeroum danzeroum merged commit 53a3ce0 into master Jun 21, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants