- Add V1 API routes for assets, ledger, and user info with complete CRUD operations - Implement authentication scopes and request validation via auth_routes.py - Extend schemas with V1-specific models for accounts, holdings, and positions - Add database queries and aggregations for P&L, performance, and account data - Include comprehensive test coverage for all V1 endpoints and integration flows - Update batch and release documentation with implementation and verification evidence - Sync project structure and runtime flows per V1 API contract requirements Closes implementation phase of BAT-001 (TrEx Basic V1 API Contract)
6.6 KiB
6.6 KiB
Portfolio Hub Runtime Flows
- Baseline Mode: observed
- Baseline Seed: .stagepilot/bootstrap/baseline.yaml
- Status: confirmed
- Owner: repository-maintainers
- Last Updated (KST): 2026-05-01 00:00
- Source Discovery / Batch: bootstrap-baseline, bat-001
- Primary Runtime: mixed
Project Summary
- PortfolioHub exposes portfolio management and trading ledger workflows through a FastAPI service and a companion CLI.
Purpose
- This document is the current approved execution-flow baseline for the project.
- It is a cross-cutting reference document for Discovery, REQ, Batch Design, Batch Verification, and implementation updates.
Scope
- Covers representative command and runtime flows.
- Does not duplicate full acceptance criteria or low-level implementation details.
Covered Entry Points
- uvicorn app.main:app :: serve the authenticated HTTP API, OpenAPI docs, and startup bootstrap hooks
- pfhub :: run operational CLI commands for health, users, portfolios, strategies, and service tokens
- alembic upgrade head :: apply ordered database schema migrations for persistent environments
Shared Components
- app/core/config.py Settings loading and environment normalization
- app/core/auth.py permission guards and auth context resolution
- app/services/* business logic for auth, users, portfolios, and strategy sets
- app/repositories/factory.py repository selection and Postgres config construction
- app/repositories/postgres.py Postgres persistence, schema bootstrap, and query execution
Flow: HTTP API Request Handling
- Uvicorn loads app.main:app, which creates the FastAPI application from create_app().
- create_app() loads Settings, registers middleware and routers, and wires exception handlers.
- During lifespan startup, the app optionally bootstraps an initial admin user when DB mode and bootstrap credentials are configured.
- Incoming requests pass through auth and permission dependencies before services mutate state or query persistence.
- Services call the repository factory, which returns PostgresPortfolioRepository only when PORTFOLIOHUB_DB_ENABLED=true.
- Routes serialize domain results into app/schemas response models or return HTTP 204 for deletion flows.
Flow: CLI Operational Command Execution
- The pfhub entrypoint builds a Typer application and injects Settings, console output, and a repository factory into AppContext.
- Command groups parse arguments, confirmations, and output format selection before invoking the relevant service or repository methods.
- Database setup commands use the shared settings layer to target the configured PostgreSQL or TimescaleDB instance.
- Read commands print table or JSON output, while write commands require explicit confirmation unless --force is supplied.
- Command failures surface as validation errors, feature-not-ready errors, or persistence and auth exceptions.
Flow Constraints
- Persistence-dependent HTTP and CLI flows require PORTFOLIOHUB_DB_ENABLED=true plus valid TimescaleDB connection settings.
- Permission levels read, trade-write, and admin must map consistently across API guards, issued tokens, and CLI mutations.
- Request validation and auth resolution should happen before persistence mutation or response rendering.
- The health endpoint remains unauthenticated so infrastructure can probe readiness without a token.
Flow: v1 API — Service-Token Authentication
- v1 endpoint receives Bearer token from Authorization header.
require_readresolves the token: checks env tokens first, then DB lookup viaget_token_principal().- If DB token: validates
token_source == "db"andtoken_type == "service", else returns HTTP 403. AuthContextis populated withuser_id,token_type,permission, andruntime_id.
Flow: v1 API — GET /v1/assets
- Service-token auth required (see above).
list_portfolios_with_strategies()fetches all portfolios from DB.- Optional
?status=<value>query param filters portfolios by status field. - For portfolios with
active_strategy_id,get_strategy_set()fetches config and JSON-parsesstrategy_params; failures fall back to{}. - Returns
AssetsResponsewithtotalandassets[]using new field names:cash,quantity,broker_type,strategy_params.
Flow: v1 API — GET /v1/user_info
- Service-token auth required. HTTP 404 if
runtime_idis None. get_user()fetches user record byuser_id.list_broker_credentials()fetches all broker credential rows for the user.- For each credential, Fernet-decrypts
encrypted_payloadusingCREDENTIAL_ENCRYPTION_KEY; decryption failures log a warning and returncredential_payload: null. - Returns
UserInfoResponsewithtrading_enabled(fromis_active),disabled_reason, andbrokers[].
Flow: v1 API — POST /v1/assets/{asset_id}/ledger/trades
- Service-token auth required with
trade-writepermission. - Validates asset existence via
repo.get(asset_id); HTTP 404 if missing. - Calls
insert_ledger_trade()with idempotency key(asset_id, order_id, execution_id). - If new record: returns HTTP 201 with
status="new". - If duplicate key with identical payload: returns HTTP 200 with
status="duplicate". - If duplicate key with different payload: returns HTTP 409 with conflict detail.
Flow: v1 API — POST /auth/service-tokens
- Admin token auth required (
require_admindependency). - Validates request body:
name,username,permission,expires_in_days/no_expiry. - Calls
AuthService.issue_service_token()which creates a new DB token withruntime_id. - Returns HTTP 201 with
token(raw value),runtime_id, andauth_tokenmetadata.
Flow: Application Startup Validation
lifespanstartup hook runs_bootstrap_initial_user()if DB enabled and bootstrap credentials configured.- If
db_enabled=True, callssettings.require_credential_encryption_key(). - If
CREDENTIAL_ENCRYPTION_KEYis not configured, raisesRuntimeErrorand aborts startup.
Current Gaps / Planned Changes
- End-to-end validation against a real PostgreSQL or TimescaleDB deployment is still pending.
- Redis and Loki are configured as supporting infrastructure but are not yet represented as explicit runtime flows.
- Broker credential write path (upsert) is available only via CLI; no HTTP API endpoint for credential registration exists yet.
Change Log
- 2026-05-01 KST: bat-001 — Added v1 API flows (service-token auth, GET /v1/assets, GET /v1/user_info, POST ledger/trades, POST /auth/service-tokens), startup validation flow.
- 2026-04-30 KST: Bootstrap baseline created from repository observation for initial StagePilot adoption.