# PortfolioHub PortfolioHub is a FastAPI service that extracts portfolio management from `jsbot-kis` and exposes it through an authenticated HTTP API. ## Current status This repository is in bootstrap phase. - FastAPI application entrypoint is available. - Token-based authentication and role checks are implemented. - Portfolio and user management API contracts are implemented. - Core portfolio domain services are ported from `jsbot-kis`. - Postgres-backed portfolio and user persistence is implemented and gated behind `PORTFOLIOHUB_DB_ENABLED=true`. ## Configuration Copy `.env.example` to `.env` and edit values as needed: ```bash cp .env.example .env ``` The application loads configuration in this order (higher priority first): 1. Environment variables 2. Variables from `.env` file 3. Default values in code When deploying to production, set environment variables directly instead of using `.env`. ### Key configuration options - **DB repository switch**: `PORTFOLIOHUB_DB_ENABLED` (enables DB-backed persistence) - **Initial user bootstrap**: `PORTFOLIOHUB_BOOTSTRAP_USERNAME`, `PORTFOLIOHUB_BOOTSTRAP_EMAIL` - **Initial user password**: `PORTFOLIOHUB_BOOTSTRAP_PASSWORD` - **Session/token TTL**: `PORTFOLIOHUB_SESSION_TOKEN_TTL_HOURS`, `PORTFOLIOHUB_CLIENT_TOKEN_DEFAULT_TTL_DAYS`, `PORTFOLIOHUB_BOT_TOKEN_DEFAULT_TTL_DAYS` - **TimescaleDB / PostgreSQL**: `TIMESCALEDB_*` (single source of DB connection settings) - **Redis**: `REDIS_*` (for caching and sessions) - **Loki**: `LOKI_*` (for centralized logging) - **Authentication**: `PORTFOLIOHUB_*_TOKENS` (bearer tokens with role-based access) For complete configuration options, see `.env.example`. ## Run locally ```bash python -m venv .venv source .venv/bin/activate pip install -e .[dev] # Configure .env cp .env.example .env # Start server uvicorn app.main:app --reload # In another terminal, run tests pytest ``` ## CLI The repository now includes a `portfoliohub` CLI that mirrors the main portfolio flows from `jsbot-kis`. ```bash portfoliohub --help portfoliohub user list portfoliohub user create --username alice --password password123 --email alice@example.com --force portfoliohub user get portfoliohub user update --username alice-updated --force portfoliohub user delete --force portfoliohub portfolio list portfoliohub portfolio status 005930:tv --recent 10 portfoliohub portfolio create 005930:tv --symbol 005930 --cash-balance 10000000 --force portfoliohub portfolio buy 005930:tv --quantity 10 --price 71000 --fee 5000 --force portfoliohub portfolio sell 005930:tv --quantity 5 --price 72000 --tax 3000 --force portfoliohub portfolio invest 005930:tv --type deposit --amount 50000 --force portfoliohub portfolio transfer 005930:tv --direction to-buffer --amount 100000 --force portfoliohub portfolio reset 005930:tv --force portfoliohub portfolio delete 005930:tv --keep-ledger --force ``` Supported commands: - `init-db` - `migrate-db` - `user list` - `user get` - `user create` - `user update` - `user delete` - `portfolio list` - `portfolio status` - `portfolio create` - `portfolio update` - `portfolio buy` - `portfolio sell` - `portfolio invest` - `portfolio transfer` - `portfolio reset` - `portfolio delete` - `health-check` Write commands ask for confirmation by default. Use `--force` to skip the prompt for scripts and automation. The CLI uses the same repository and settings layer as the HTTP API. To target the external TimescaleDB, set `PORTFOLIOHUB_DB_ENABLED=true` and provide `TIMESCALEDB_*` values in the environment or `.env`. Initialize a new database explicitly before the first use: ```bash PORTFOLIOHUB_DB_ENABLED=true portfoliohub init-db PORTFOLIOHUB_DB_ENABLED=true portfoliohub health-check PORTFOLIOHUB_DB_ENABLED=true portfoliohub portfolio list ``` `init-db` will: - connect to the maintenance database, defaulting to `postgres` - create the target database if it does not exist - run Alembic `upgrade head` `migrate-db` will: - connect to the target database - run Alembic `upgrade head` - apply any future schema revisions in order This repository now uses Alembic for versioned schema migrations. Future schema changes should be added under `migrations/versions`. ## Docs Sync Guardrail To keep implementation and specification documents in sync, this repository provides an automated check. Rules enforced: - If files under `app/` change, at least one `docs/technical/` document must be updated in the same commit/PR. - If files under `app/api/` or `app/schemas/` change, `docs/technical/api-contracts.md` must be updated in the same commit/PR. - If files under `migrations/versions/` change, `docs/technical/persistence-and-migrations.md` must be updated in the same commit/PR. - Changed migration revision IDs must appear in `docs/technical/persistence-and-migrations.md`. Enable local pre-commit check: ```bash pip install -e .[dev] pre-commit install ``` Run manually: ```bash python3 scripts/check_docs_sync.py --staged ``` CI check: - GitHub Actions workflow: `.github/workflows/docs-sync-check.yml` - Runs automatically on pull requests. ## Authentication model PortfolioHub currently supports bearer tokens with three permission levels. - `read`: list and status endpoints - `trade-write`: mutation endpoints such as buy, sell, invest, transfer, reset - `admin`: delete, user management, and future operational actions ## User management User management is exposed through both HTTP API and CLI. - API base route: `/users` - Permission: `admin` only - Supported operations: list, get, create, update, delete Frontend and app authentication is exposed through `/auth`. - `POST /auth/login`: username/password login, returns bearer session token - `GET /auth/tokens`: list current user's issued tokens - `POST /auth/tokens`: issue a client token for app/script usage - `DELETE /auth/tokens/{token_id}`: revoke a previously issued token - `POST /auth/bots`: create external bot principal (admin only) - `GET /auth/bots`: list bot principals (admin only) - `POST /auth/bots/{bot_id}/tokens`: issue bot API key with expiration (admin only) - `GET /auth/bots/{bot_id}/tokens`: list bot keys (admin only) - `DELETE /auth/bots/{bot_id}/tokens/{token_id}`: revoke bot key (admin only) - `DELETE /auth/bots/{bot_id}`: deactivate bot and revoke linked keys (admin only) Example API calls: ```bash curl -X GET "http://localhost:8000/users" \ -H "Authorization: Bearer " curl -X POST "http://localhost:8000/users" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"username": "alice", "email": "alice@example.com"}' ``` The default `.env.example` includes example tokens for development. When `PORTFOLIOHUB_DB_ENABLED=true` and both `PORTFOLIOHUB_BOOTSTRAP_USERNAME` and `PORTFOLIOHUB_BOOTSTRAP_PASSWORD` are set, the app creates that admin user automatically on startup only if the `users` table is empty. This is intended for first-run bootstrap, not recurring synchronization. ## Planned next steps 1. Apply and verify Alembic migrations against a real PostgreSQL/Timescale instance. 2. Add integration tests for DB-backed portfolio and user flows. 3. Design token-to-user mapping if ownership or user-scoped authorization is needed later.