Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

63 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WalletOps Companion

Personal ops console for simulated wallet events. Partners post signed webhooks; Postgres stores them idempotently; a Go worker claims and processes them against alert rules; a Flutter client lists events and can request a schema-checked summary.

No real custody, keys, or on-chain sends.

Why the backend matters

The interview-friendly core is reliability around ingest and jobs:

Concern Behavior
Forged webhooks HMAC-SHA256 over the raw body (X-Signature: sha256=<hex>)
Duplicate delivery Unique (user_id, idempotency_key); replay returns the same event (200)
Concurrent workers FOR UPDATE SKIP LOCKED claim — safe under two pollers
Crash mid-process claimed_at lease; stale processing rows become claimable again
Retries Failed attempts back off (capped at 60s) up to 5 tries

Open api/internal/webhook/handler_test.go (replay) and api/internal/worker/worker_test.go (TestConcurrentClaimNoDoubleProcess, TestReclaimExpiredProcessingLease).

Architecture

See docs/architecture.md. Threat notes: docs/threat-model.md.

sequenceDiagram
  participant P as Partner
  participant A as API
  participant D as DB
  participant W as Worker
  participant M as Mobile
  P->>A: HMAC webhook
  A->>D: pending event
  W->>D: claim + process
  M->>A: list events / summarize
Loading

Env

Copy .env.example.env (compose already injects defaults for local):

Var Purpose
DATABASE_URL Postgres DSN
JWT_SECRET Access token signing
WEBHOOK_SECRET HMAC for /v1/webhooks/events
AI_PROVIDER mock (default) or openai
AI_API_KEY Required if openai
HTTP_ADDR API bind (:8080)

Demo (< 5 minutes)

# 1) API + Postgres
docker compose up --build -d
curl -s http://127.0.0.1:8080/v1/health
# expect status=ok, worker ticks, queue.by_status

# 2) Seed user + two signed events (maps user_ref=demo-user-1)
./scripts/seed_webhooks.sh

# 3) Optional: create a rule via curl after login from seed output,
#    or use the mobile app (Events → Rules).

# 4) Mobile
cd mobile
fvm flutter pub get
# Simulator / desktop (API on this machine):
fvm flutter run --dart-define=API_BASE=http://127.0.0.1:8080
# Physical iPhone/Android on the same Wi‑Fi — use your Mac LAN IP, not 127.0.0.1:
#   ipconfig getifaddr en0
# fvm flutter run --dart-define=API_BASE=http://192.168.x.x:8080
# Android emulator: API_BASE=http://10.0.2.2:8080

In the app: sign in as demo-user-1@walletops.local / ops-secret-1Events → Run live demo → confirm. Watch each webhook move PENDING → PROCESSING → PROCESSED (compose holds processing ~2.5s so the queue is readable). Open an event for pipeline steps → Explain. Check Rules for the demo alert rule the worker matches.

POST /v1/demo/simulate (auth) inserts fresh pending events for the journey; partner HMAC ingest remains POST /v1/webhooks/events.

If iOS install crashes at launch after a Podfile change: cd mobile/ios && pod install && cd .. then fvm flutter clean && fvm flutter run .... Clear a stale signing cert with flutter config --clear-ios-signing-settings.

Tests

CI runs the same checks on every pull request (see .github/workflows/ci.yml): Go tests against Postgres, Flutter analyze + test against a Compose API.

# API (stop api container first if it races the worker)
cd api && DATABASE_URL='postgres://walletops:walletops@localhost:5432/walletops?sslmode=disable' go test ./...

# Mobile (API up on :8080 for integration tests)
cd mobile && flutter pub get && flutter analyze && flutter test --dart-define=API_BASE=http://127.0.0.1:8080

Module path: github.com/omid/walletops/api.

About

Flutter + Go ops console for simulated wallet events — HMAC webhooks, idempotent ingest, retrying worker, alert rules.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages