From 5d3884fd4a057effdd6dcbc4b5ff40971f0b98ac Mon Sep 17 00:00:00 2001 From: Justin Ko Date: Thu, 23 Apr 2026 05:25:26 +0000 Subject: [PATCH] chore: rename CLI to pfhub, update service-token command, and update docs/tests accordingly --- README.md | 72 +++++++++++++++++++++++------------------------ app/cli/main.py | 4 +-- pyproject.toml | 3 +- tests/test_cli.py | 11 ++++---- 4 files changed, 44 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 88c8c54..2037cb5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# PortfolioHub +# Portfolio Hub -PortfolioHub is a FastAPI service that extracts portfolio management from `jsbot-kis` and exposes it through an authenticated HTTP API. +Portfolio Hub is a FastAPI service that extracts portfolio management from `jsbot-kis` and exposes it through an authenticated HTTP API. ## Current status @@ -10,7 +10,7 @@ This repository is in bootstrap phase. - 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`. +- Postgres-backed portfolio and user persistence is implemented and gated behind `pfhub_DB_ENABLED=true`. ## Configuration @@ -29,14 +29,14 @@ When deploying to production, set environment variables directly instead of usin ### 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` +- **DB repository switch**: `pfhub_DB_ENABLED` (enables DB-backed persistence) +- **Initial user bootstrap**: `pfhub_BOOTSTRAP_USERNAME`, `pfhub_BOOTSTRAP_EMAIL` +- **Initial user password**: `pfhub_BOOTSTRAP_PASSWORD` +- **Session/token TTL**: `pfhub_SESSION_TOKEN_TTL_HOURS`, `pfhub_CLIENT_TOKEN_DEFAULT_TTL_DAYS`, `pfhub_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) +- **Authentication**: `pfhub_*_TOKENS` (bearer tokens with role-based access) For complete configuration options, see `.env.example`. @@ -73,7 +73,7 @@ Default endpoints exposed by `docker-compose.local-test.yml`: Typical `.env` values for this local setup: ```env -PORTFOLIOHUB_DB_ENABLED=true +pfhub_DB_ENABLED=true TIMESCALEDB_HOST=127.0.0.1 TIMESCALEDB_PORT=5432 TIMESCALEDB_USER=portfolio_hub_user @@ -95,28 +95,28 @@ docker compose -f docker-compose.local-test.yml down ## CLI -The repository now includes a `portfoliohub` CLI that mirrors the main portfolio flows from `jsbot-kis`. +The repository now includes a `pfhub` CLI that mirrors the main portfolio flows from `jsbot-kis`. The same commands are also available through the shorter alias `phub`. ```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 bot token issue --name nightly --ttl-days 30 -portfoliohub bot token issue --name permanent --no-expiry -portfoliohub bot token revoke --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 +pfhub --help +pfhub user list +pfhub user create --username alice --password password123 --email alice@example.com --force +pfhub user get +pfhub user update --username alice-updated --force +pfhub user delete --force +pfhub service-token issue --name nightly --ttl-days 30 +pfhub service-token issue --name permanent --no-expiry +pfhub service-token revoke --force +pfhub portfolio list +pfhub portfolio status 005930:tv --recent 10 +pfhub portfolio create 005930:tv --symbol 005930 --cash-balance 10000000 --force +pfhub portfolio buy 005930:tv --quantity 10 --price 71000 --fee 5000 --force +pfhub portfolio sell 005930:tv --quantity 5 --price 72000 --tax 3000 --force +pfhub portfolio invest 005930:tv --type deposit --amount 50000 --force +pfhub portfolio transfer 005930:tv --direction to-buffer --amount 100000 --force +pfhub portfolio reset 005930:tv --force +pfhub portfolio delete 005930:tv --keep-ledger --force ``` Supported commands: @@ -128,8 +128,8 @@ Supported commands: - `user create` - `user update` - `user delete` -- `bot token issue` -- `bot token revoke` +- `service-token issue` +- `service-token revoke` - `portfolio list` - `portfolio status` - `portfolio create` @@ -151,14 +151,14 @@ Bot token issue policy: - `--no-expiry`는 관리자 권한에서만 허용된다. - 토큰 원문은 발급 응답 1회 이후 마스킹된 값으로만 출력/기록된다. -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`. +The CLI uses the same repository and settings layer as the HTTP API. To target the external TimescaleDB, set `pfhub_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 +pfhub_DB_ENABLED=true pfhub init-db +pfhub_DB_ENABLED=true pfhub health-check +pfhub_DB_ENABLED=true pfhub portfolio list ``` `init-db` will: @@ -206,7 +206,7 @@ CI check: ## Authentication model -PortfolioHub currently supports bearer tokens with three permission levels. +pfhub currently supports bearer tokens with three permission levels. - `read`: list and status endpoints - `trade-write`: mutation endpoints such as buy, sell, invest, transfer, reset @@ -247,7 +247,7 @@ curl -X POST "http://localhost:8000/users" \ 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. +When `pfhub_DB_ENABLED=true` and both `pfhub_BOOTSTRAP_USERNAME` and `pfhub_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 diff --git a/app/cli/main.py b/app/cli/main.py index 231a22c..33c7950 100644 --- a/app/cli/main.py +++ b/app/cli/main.py @@ -9,7 +9,7 @@ import typer from rich.console import Console from app.cli.commands.health import register_health_commands -from app.cli.commands.bot_tokens import bot_app +from app.cli.commands.bot_tokens import token_app from app.cli.commands.portfolio import portfolio_app from app.cli.commands.strategy import strategy_app from app.cli.commands.user import user_app @@ -50,7 +50,7 @@ def create_app( app.add_typer(portfolio_app, name="portfolio") app.add_typer(strategy_app, name="strategy") app.add_typer(user_app, name="user") - app.add_typer(bot_app, name="bot") + app.add_typer(token_app, name="service-token") register_health_commands(app) return app diff --git a/pyproject.toml b/pyproject.toml index b467d3c..60e7ca6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,8 +20,7 @@ dependencies = [ ] [project.scripts] -portfoliohub = "app.cli.main:main" -phub = "app.cli.main:main" +pfhub = "app.cli.main:main" [project.optional-dependencies] dev = [ diff --git a/tests/test_cli.py b/tests/test_cli.py index 8f4b143..4141cac 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -830,7 +830,7 @@ def test_cli_help_exposes_bot_token_commands() -> None: repo = FakeRepo(_portfolio()) runner = build_runner(repo) - result = runner.invoke(runner.app, ["bot", "token", "--help"]) + result = runner.invoke(runner.app, ["service-token", "--help"]) assert result.exit_code == 0 assert "issue" in result.stdout @@ -843,7 +843,7 @@ def test_cli_bot_token_issue_supports_json() -> None: result = runner.invoke( runner.app, - ["--format", "json", "bot", "token", "issue", "bot-1", "--name", "nightly"], + ["--format", "json", "service-token", "issue", "bot-1", "--name", "nightly"], ) assert result.exit_code == 0 @@ -861,8 +861,7 @@ def test_cli_bot_token_issue_rejects_conflicting_expiry_options() -> None: result = runner.invoke( runner.app, [ - "bot", - "token", + "service-token", "issue", "bot-1", "--ttl-days", @@ -890,7 +889,7 @@ def test_cli_bot_token_revoke_can_abort() -> None: result = runner.invoke( runner.app, - ["bot", "token", "revoke", "bot-1", token.id], + ["service-token", "revoke", "bot-1", token.id], input="n\n", ) @@ -913,7 +912,7 @@ def test_cli_bot_token_revoke_force_succeeds() -> None: result = runner.invoke( runner.app, - ["--format", "json", "bot", "token", "revoke", "bot-1", token.id, "--force"], + ["--format", "json", "service-token", "revoke", "bot-1", token.id, "--force"], ) assert result.exit_code == 0