hdb is the crypto accounting database CLI in this monorepo.
Source location: src/apps/hdb
For the local web UI over hdb data, see ../hdb-portal/README.md.
- Node.js
>=20 - npm
- local PostgreSQL
Install dependencies from the repo root:
npm installConfigure env in the default helper path:
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/helper"
cp .env.example "${XDG_CONFIG_HOME:-$HOME/.config}/helper/.env"For hdb, set these required Postgres values in the env file:
HELPER_POSTGRES_DATABASE=hdb
HELPER_POSTGRES_USERNAME=hdb_user
HELPER_POSTGRES_PASSWORD=hdb_passwordOptional override:
export HELPER_ENV_FILE=/absolute/path/to/.envLocal PostgreSQL setup details are in README.postgres.md.
Run from TypeScript source:
tsx src/apps/hdb/cli.ts --helptsx src/apps/hdb/cli.ts health
Run built CLI:
npm run buildnode dist/apps/hdb/cli.js --help
Install binary in your shell:
npm linkhdb --help
hdb healthhdb system rebuild-all- rebuilds all input-derived tables sequentially
- excludes Coinbase orders
- stages: Coinbase transactions -> Coinbase balances -> CoinTracker transactions/balances -> CoinTracker gains
hdb coinbase balances list <asset>assetsupports colon-separated values--jsonprints structured troubleshooting output--json-file <path>writes the same structured payload to disk--currentlive check requires--remote
hdb coinbase balances snapshot--jsonprints structured troubleshooting output--json-file <path>writes the same structured payload to disk--currentlive check requires--remote
hdb coinbase balances trace <asset>--jsonprints structured troubleshooting output--json-file <path>writes the same structured payload to disk
hdb coinbase balances rebuildhdb coinbase lots analyze <asset>hdb coinbase lots analyze-allhdb coinbase lots compare <asset>hdb coinbase lots compare-all- supports
--csvand--f8949exports
- supports
hdb coinbase orders show <orderId>--jsonprints{ row, meta }--json-file <path>writes the same structured payload to disk
hdb coinbase orders inspect <orderId>--jsonprints{ row, meta }--json-file <path>writes the same structured payload to disk
hdb coinbase orders fees [productId]hdb coinbase orders import-one <orderId>- requires explicit live mode:
--remote
- requires explicit live mode:
hdb coinbase orders rebuild- source selection required:
--cacheor--remote
- source selection required:
hdb coinbase orders sync- requires source selection:
--cacheor--remote
- requires source selection:
hdb coinbase transactions list [asset]--jsonprints{ rows, filters, meta }--json-file <path>writes the same structured payload to disk
hdb coinbase transactions summary [asset]--jsonprints{ rows, totals, filters, meta }--json-file <path>writes the same structured payload to disk
hdb coinbase transactions show [id]--jsonprints{ rows, filters, meta }--json-file <path>writes the same structured payload to disk
hdb coinbase transactions add-manual <asset>hdb coinbase transactions import-statement <filepath>hdb coinbase transactions rebuild- input directory:
--input-dir <dir>or${HELPER_HDB_ROOT_DIR}/input/coinbase-transactions
- input directory:
hdb coinbase transactions analyze-nav- requires explicit live mode:
--remote
- requires explicit live mode:
Coinbase migration status and next slices are tracked in:
hdb cointracker balances list [currency]--jsonprints{ rows, filters, meta }--json-file <path>writes the same structured payload to disk
hdb cointracker balances rebuildhdb cointracker gains list [assets]- export flags:
--csv,--f8949,--headers,--pages - totals/format:
--totals,--raw,--json --json-file <path>writes the same structured payload to disk
- export flags:
hdb cointracker gains summary [assets]- export flags:
--csv,--f8949,--headers,--pages - totals/format:
--totals,--raw,--json --json-file <path>writes the same structured payload to disk
- export flags:
hdb cointracker gains rebuild- input directory:
--input-dir <dir>or${HELPER_HDB_ROOT_DIR}/input/cointracker-capital-gains
- input directory:
hdb cointracker gains analyze-usdc- use
--bucketsor--interval <day|week|month|quarter|year>
- use
hdb cointracker transactions list [asset]--jsonprints{ rows, filters, meta }--json-file <path>writes the same structured payload to disk
hdb cointracker transactions summary [asset]--jsonprints{ rows, filters, meta }--json-file <path>writes the same structured payload to disk
hdb cointracker transactions rebuild- input directory:
--input-dir <dir>or${HELPER_HDB_ROOT_DIR}/input/cointracker-transactions - also rebuilds
cointracker_balances_ledger
- input directory:
Use hdb <command path> --help for option details.
Prefer these two local-only paths when validating hdb correctness:
hdb ... --json- best for repeated debugging and agent-assisted inspection
- stable machine-readable output with normalized filters and row counts
psqlwith the localhdb_readonlyrole- best for ad hoc SQL when the existing command surface is not enough
- use only for local read-only inspection
Examples:
hdb coinbase transactions list btc --from 2026-01-01 --to 2026-02-01 --json
hdb coinbase balances trace eth --to 2026-02-01T00:00:00Z --json
hdb cointracker gains summary btc:eth --totals --json
psql "postgresql://hdb_readonly:readonly_password@localhost:5432/hdb" -c "select count(*) from coinbase_transactions;"Structured JSON (--json / --json-file) is read-only and intended for troubleshooting. It is not available on mutation commands. For CoinTracker gains, structured JSON cannot be combined with --csv or --f8949.
This section tracks legacy old.js TODOs that are still relevant for the migrated hdb app.
Goal: support incremental ingestion of new CSVs by filename (without full rebuild), with explicit conflict handling.
Current state: Coinbase supports import-statement <filepath> and both Coinbase/CoinTracker support directory rebuilds. Conflict replacement is available for manual Coinbase inserts only.
Needed:
- Add incremental file import command(s) for CoinTracker transactions similar to Coinbase statement import.
- Add explicit conflict policy (
error,skip,replace) for CSV imports/rebuilds. - For replace paths on Coinbase transactions, trigger or enforce dependent recomputation (at minimum balances, and potentially lots) to keep derived data consistent.
Goal: map trade transactions to order lifecycle and fill records for stronger auditability and reconciliation.
Current state: coinbase_orders is stored, but coinbase_transactions rows do not contain order_id, and there is no fill-level table.
Needed:
- Add a
coinbase_fillsmodel (or equivalent) with fill-level attributes, includingorder_id. - Build a deterministic transaction-to-fill linking path where possible.
- Add explicit unmatched/ambiguous handling plus optional manual overrides for hard cases.
Goal: compute point-in-time NAV over a historical range, not only current snapshot NAV.
Current state: coinbase transactions analyze-nav uses current live account balances and current product prices, not historical prices.
Needed:
- Historical price source and ingestion pipeline.
- Local storage for historical candles/prices keyed by product and interval.
- Valuation logic that joins historical holdings with historical prices at consistent timestamps.
- Policy for missing candle data (fail, nearest, interpolation).
Reference:
- Coinbase Advanced Trade candles API: https://docs.cdp.coinbase.com/api-reference/advanced-trade-api/rest-api/products/get-product-candles
Goal: extend CoinTracker balance ledger to optionally reference matched Coinbase transaction IDs for cross-system reconciliation.
Current state: CoinTracker balances ledger is implemented and references cointracker_transaction_id, but it does not store Coinbase linkage.
Needed:
- Add Coinbase linkage field(s) or a dedicated mapping table.
- Build matching heuristics (timestamp window, asset, quantity, type).
- Persist match confidence/status and allow unresolved rows.
Goal: provide a reproducible reconciliation report that explains differences between CoinTracker PnL and Coinbase NAV.
Current state: both views exist, but there is no dedicated decomposition/reporting workflow.
Needed:
- Define exact reconciliation semantics (realized/unrealized, cash handling, fees, time windows, excluded assets).
- Add command/report output that breaks deltas into categories (pricing basis, unmatched transfers, fees, synthetic rows, timing differences).
- Add regression tests over fixed fixtures to prevent silent drift in reconciliation logic.
- USDC day-level grouping is available now via
hdb cointracker gains analyze-usdc --interval day.
npm run lintnpm run typechecknpm run testnpm run validate:hdb:inputs- offline CSV parser validation for
${repoRoot}/data/input/* - optional input root override:
npm run validate:hdb:inputs -- --input-root <dir>
- offline CSV parser validation for
npm run buildnpm run release:check
To keep files easy to scan as hdb grows, avoid generic repeated names.
- Command registration files:
register-<domain>-commands.ts - Command handlers:
<domain>-handlers.ts - Command option schemas:
<domain>-options.ts - Shared date/time helpers:
date-range-utils.ts - DB entrypoint:
db-client.ts - DB pool module:
postgres-pool.ts - DB repositories:
<domain>-repository.ts - DB SQL modules:
<domain>-sql.ts - DB mapping modules:
<domain>-mappers.ts - General rule: prefer explicit, domain-scoped filenames over
register.ts,handlers.ts, ororders.ts.
Project workflow and standards are in CONTRIBUTING.md.