- 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)
114 lines
6.6 KiB
Markdown
114 lines
6.6 KiB
Markdown
# 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`
|
|
|
|
1. Uvicorn loads app.main:app, which creates the FastAPI application from create_app().
|
|
2. create_app() loads Settings, registers middleware and routers, and wires exception handlers.
|
|
3. During lifespan startup, the app optionally bootstraps an initial admin user when DB mode and bootstrap credentials are configured.
|
|
4. Incoming requests pass through auth and permission dependencies before services mutate state or query persistence.
|
|
5. Services call the repository factory, which returns PostgresPortfolioRepository only when PORTFOLIOHUB_DB_ENABLED=true.
|
|
6. Routes serialize domain results into app/schemas response models or return HTTP 204 for deletion flows.
|
|
|
|
## Flow: `CLI Operational Command Execution`
|
|
|
|
1. The pfhub entrypoint builds a Typer application and injects Settings, console output, and a repository factory into AppContext.
|
|
2. Command groups parse arguments, confirmations, and output format selection before invoking the relevant service or repository methods.
|
|
3. Database setup commands use the shared settings layer to target the configured PostgreSQL or TimescaleDB instance.
|
|
4. Read commands print table or JSON output, while write commands require explicit confirmation unless --force is supplied.
|
|
5. 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`
|
|
|
|
1. v1 endpoint receives Bearer token from Authorization header.
|
|
2. `require_read` resolves the token: checks env tokens first, then DB lookup via `get_token_principal()`.
|
|
3. If DB token: validates `token_source == "db"` and `token_type == "service"`, else returns HTTP 403.
|
|
4. `AuthContext` is populated with `user_id`, `token_type`, `permission`, and `runtime_id`.
|
|
|
|
## Flow: `v1 API — GET /v1/assets`
|
|
|
|
1. Service-token auth required (see above).
|
|
2. `list_portfolios_with_strategies()` fetches all portfolios from DB.
|
|
3. Optional `?status=<value>` query param filters portfolios by status field.
|
|
4. For portfolios with `active_strategy_id`, `get_strategy_set()` fetches config and JSON-parses `strategy_params`; failures fall back to `{}`.
|
|
5. Returns `AssetsResponse` with `total` and `assets[]` using new field names: `cash`, `quantity`, `broker_type`, `strategy_params`.
|
|
|
|
## Flow: `v1 API — GET /v1/user_info`
|
|
|
|
1. Service-token auth required. HTTP 404 if `runtime_id` is None.
|
|
2. `get_user()` fetches user record by `user_id`.
|
|
3. `list_broker_credentials()` fetches all broker credential rows for the user.
|
|
4. For each credential, Fernet-decrypts `encrypted_payload` using `CREDENTIAL_ENCRYPTION_KEY`; decryption failures log a warning and return `credential_payload: null`.
|
|
5. Returns `UserInfoResponse` with `trading_enabled` (from `is_active`), `disabled_reason`, and `brokers[]`.
|
|
|
|
## Flow: `v1 API — POST /v1/assets/{asset_id}/ledger/trades`
|
|
|
|
1. Service-token auth required with `trade-write` permission.
|
|
2. Validates asset existence via `repo.get(asset_id)`; HTTP 404 if missing.
|
|
3. Calls `insert_ledger_trade()` with idempotency key `(asset_id, order_id, execution_id)`.
|
|
4. If new record: returns HTTP 201 with `status="new"`.
|
|
5. If duplicate key with identical payload: returns HTTP 200 with `status="duplicate"`.
|
|
6. If duplicate key with different payload: returns HTTP 409 with conflict detail.
|
|
|
|
## Flow: `v1 API — POST /auth/service-tokens`
|
|
|
|
1. Admin token auth required (`require_admin` dependency).
|
|
2. Validates request body: `name`, `username`, `permission`, `expires_in_days` / `no_expiry`.
|
|
3. Calls `AuthService.issue_service_token()` which creates a new DB token with `runtime_id`.
|
|
4. Returns HTTP 201 with `token` (raw value), `runtime_id`, and `auth_token` metadata.
|
|
|
|
## Flow: `Application Startup Validation`
|
|
|
|
1. `lifespan` startup hook runs `_bootstrap_initial_user()` if DB enabled and bootstrap credentials configured.
|
|
2. If `db_enabled=True`, calls `settings.require_credential_encryption_key()`.
|
|
3. If `CREDENTIAL_ENCRYPTION_KEY` is not configured, raises `RuntimeError` and 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. |