Files
portfolio-hub/docs/db-schema-spec.md
T

5.1 KiB

PortfolioHub DB Schema Specification

1. Purpose

This document defines the database schema in an AI-agent-friendly format.

  • Source of truth: Alembic revisions in migrations/versions
  • Current baseline revision: 20260403_0002
  • Baseline files:
    • migrations/versions/20260403_0001_initial_portfolio_schema.py
    • migrations/versions/20260403_0002_strategy_set_columns.py

2. Scope

Schema objects covered by baseline revision:

  • strategy_sets
  • portfolios
  • portfolio_ledger
  • secondary indexes
  • Timescale hypertable conversion rule for portfolio_ledger

3. Conventions

  • Data type names follow SQLAlchemy/Alembic declaration.
  • NULL means nullable.
  • Default means DB-level server_default where defined.
  • Relationship columns are documented even when no FK constraint exists.

4. Tables

4.1 strategy_sets

Purpose:

  • Stores normalized strategy configuration snapshots.

Columns:

Column Type Null Default Constraints / Notes
id Text NO - Primary Key
name Text NO - Strategy name, part of unique pair
config Text NO "" Strategy config payload, part of unique pair
nick Text NO - Unique strategy set nickname
created_at DateTime(timezone=True) NO NOW() Creation timestamp

Constraints:

  • Primary key: id
  • Unique: uq_strategy_sets_name_config on (name, config)
  • Unique: uq_strategy_sets_nick on (nick)

4.2 portfolios

Purpose:

  • Stores current portfolio state and strategy linkage.

Columns:

Column Type Null Default Constraints / Notes
portfolio_id Text NO - Primary Key
broker Text NO "kis" Broker code
status Text NO "enabled" Portfolio status
symbol Text NO - Trading symbol
strategy_name Text NO "" Strategy label
strategy_params JSONB NO '{}'::jsonb Strategy parameters
cash_balance Float NO - Current cash balance
asset_quantity Float NO - Current asset quantity
asset_price Float NO 0 Current price snapshot
profit_buffer Float NO 0 Profit buffer amount
current_strategy_set_id Text YES - Logical reference to strategy_sets.id (no FK)
created_at DateTime(timezone=True) NO NOW() Creation timestamp
updated_at DateTime(timezone=True) NO NOW() Last update timestamp
last_trade_at DateTime(timezone=True) YES - Last trade time

Constraints:

  • Primary key: portfolio_id
  • Foreign key constraints: none in baseline

4.3 portfolio_ledger

Purpose:

  • Stores append-like ledger snapshots per portfolio action.

Columns:

Column Type Null Default Constraints / Notes
portfolio_id Text NO - Logical reference to portfolios.portfolio_id (no FK)
recorded_at DateTime(timezone=True) NO - Event timestamp
action Text NO - Action type
price Float NO - Trade/valuation unit price
quantity Float NO - Quantity delta
fee_amount Float NO 0 Fees
tax_amount Float NO 0 Taxes
cash_balance_after Float NO - Post-action cash
asset_quantity_after Float NO - Post-action asset quantity
total_value_after Float NO - Post-action total value
profit_buffer_after Float NO 0 Post-action profit buffer
strategy_set_id Text NO "legacy" Logical strategy set reference
note Text NO "" Operator/system note

Constraints:

  • Primary key: none in baseline
  • Foreign key constraints: none in baseline

5. Indexes

5.1 idx_portfolio_ledger_portfolio_time

  • Table: portfolio_ledger
  • Columns/expressions: (portfolio_id, recorded_at DESC)
  • Unique: no
  • Intent: fetch recent ledger entries per portfolio efficiently.

5.2 idx_portfolios_broker_status_updated

  • Table: portfolios
  • Columns/expressions: (broker, status, updated_at DESC)
  • Unique: no
  • Intent: speed list/filter queries by broker/status and recency.

6. TimescaleDB Behavior

Conditional behavior in migration upgrade:

  • Checks whether extension timescaledb exists.
  • If present, executes:

create_hypertable('portfolio_ledger', 'recorded_at', if_not_exists => TRUE)

Implication:

  • portfolio_ledger acts as a hypertable in environments with TimescaleDB extension enabled.

7. Integrity Notes

Current baseline intentionally has no DB-level FK constraints.

  • Logical relations are managed by application/repository logic.
  • When adding FK constraints in future migrations, update this document and include migration IDs.

8. Change Management Rule

When schema changes:

  1. Add/modify Alembic revision under migrations/versions.
  2. Update this document in the same commit.
  3. Keep revision mapping table below in sync.

9. Revision Mapping

Revision ID File Summary
20260403_0001 migrations/versions/20260403_0001_initial_portfolio_schema.py Initial schema for strategy sets, portfolios, ledger, indexes, optional hypertable
20260403_0002 migrations/versions/20260403_0002_strategy_set_columns.py Rename strategy_name->name, strategy_config->config, add unique nick