feat: add portfolio ownership model, auth guards, and migration

This commit is contained in:
2026-04-14 00:13:34 +09:00
parent e89690b1dd
commit 9787cf3159
22 changed files with 681 additions and 70 deletions
+33 -16
View File
@@ -70,6 +70,7 @@ _SELECT_PORTFOLIO = """
profit_buffer,
active_strategy_id,
avabile_strategies,
owner_user_id,
created_at,
updated_at,
last_trade_at
@@ -217,6 +218,7 @@ class PostgresPortfolioRepository:
status TEXT NOT NULL DEFAULT 'enabled',
name TEXT NOT NULL,
symbol TEXT NOT NULL,
owner_user_id TEXT,
cash_balance DOUBLE PRECISION NOT NULL,
asset_quantity DOUBLE PRECISION NOT NULL,
asset_price DOUBLE PRECISION NOT NULL DEFAULT 0,
@@ -230,6 +232,7 @@ class PostgresPortfolioRepository:
"""
)
cur.execute("ALTER TABLE portfolios ADD COLUMN IF NOT EXISTS name TEXT")
cur.execute("ALTER TABLE portfolios ADD COLUMN IF NOT EXISTS owner_user_id TEXT")
cur.execute("UPDATE portfolios SET name = symbol WHERE name IS NULL OR name = ''")
cur.execute("ALTER TABLE portfolios ALTER COLUMN name SET NOT NULL")
cur.execute(
@@ -363,9 +366,10 @@ class PostgresPortfolioRepository:
profit_buffer=float(row[8]),
active_strategy_id=row[9] if len(row) > 9 else None,
avabile_strategies=avabile_strategies,
created_at=row[11] if len(row) > 11 else None,
updated_at=row[12] if len(row) > 12 else None,
last_trade_at=row[13] if len(row) > 13 else None,
owner_user_id=row[11] if len(row) > 11 else None,
created_at=row[12] if len(row) > 12 else None,
updated_at=row[13] if len(row) > 13 else None,
last_trade_at=row[14] if len(row) > 14 else None,
)
@staticmethod
@@ -726,6 +730,7 @@ class PostgresPortfolioRepository:
status: str = "enabled",
active_strategy_id: str | None = None,
avabile_strategies: list[str] | None = None,
owner_user_id: str | None = None,
initial_cash: float = 0.0,
) -> Portfolio:
self.ensure_schema()
@@ -734,10 +739,10 @@ class PostgresPortfolioRepository:
"""
INSERT INTO portfolios (
portfolio_id, broker, status, name, symbol,
cash_balance, asset_quantity, asset_price, profit_buffer,
owner_user_id, cash_balance, asset_quantity, asset_price, profit_buffer,
active_strategy_id, avabile_strategies
)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
ON CONFLICT (portfolio_id) DO NOTHING
""",
(
@@ -746,6 +751,7 @@ class PostgresPortfolioRepository:
status,
name or symbol,
symbol,
owner_user_id,
float(initial_cash),
0.0,
0.0,
@@ -762,6 +768,7 @@ class PostgresPortfolioRepository:
self,
portfolio_id: str,
*,
owner_user_id: str,
broker: str,
status: str,
name: str,
@@ -782,13 +789,13 @@ class PostgresPortfolioRepository:
"""
INSERT INTO portfolios (
portfolio_id, broker, status, name, symbol,
cash_balance, asset_quantity, asset_price, profit_buffer,
owner_user_id, cash_balance, asset_quantity, asset_price, profit_buffer,
active_strategy_id, avabile_strategies
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
RETURNING
portfolio_id, broker, status, name, symbol,
cash_balance, asset_quantity, asset_price, profit_buffer,
active_strategy_id, avabile_strategies, created_at, updated_at, last_trade_at
active_strategy_id, avabile_strategies, owner_user_id, created_at, updated_at, last_trade_at
""",
(
portfolio_id,
@@ -796,6 +803,7 @@ class PostgresPortfolioRepository:
status,
name,
symbol,
owner_user_id,
float(cash_balance),
float(asset_quantity),
float(asset_price),
@@ -842,14 +850,20 @@ class PostgresPortfolioRepository:
RETURNING
portfolio_id, broker, status, name, symbol,
cash_balance, asset_quantity, asset_price, profit_buffer,
active_strategy_id, avabile_strategies, created_at, updated_at, last_trade_at
active_strategy_id, avabile_strategies, owner_user_id, created_at, updated_at, last_trade_at
""",
(*params, portfolio_id),
)
row = cur.fetchone()
return self._row_to_portfolio(row)
def list_portfolios(self, *, broker: str | None = None, status: str | None = None) -> list[Portfolio]:
def list_portfolios(
self,
*,
broker: str | None = None,
status: str | None = None,
owner_user_id: str | None = None,
) -> list[Portfolio]:
self.ensure_schema()
query = _SELECT_PORTFOLIO
clauses: list[str] = []
@@ -860,6 +874,9 @@ class PostgresPortfolioRepository:
if status is not None:
clauses.append("status = %s")
params.append(status)
if owner_user_id is not None:
clauses.append("owner_user_id = %s")
params.append(owner_user_id)
if clauses:
query += "WHERE " + " AND ".join(clauses) + " "
query += "ORDER BY updated_at DESC, portfolio_id ASC"
@@ -1041,9 +1058,9 @@ class PostgresPortfolioRepository:
last_trade_at = NULL
WHERE portfolio_id = %s
RETURNING
portfolio_id, broker, status, symbol,
portfolio_id, broker, status, name, symbol,
cash_balance, asset_quantity, asset_price, profit_buffer,
active_strategy_id, avabile_strategies, created_at, updated_at, last_trade_at
active_strategy_id, avabile_strategies, owner_user_id, created_at, updated_at, last_trade_at
""",
(portfolio_id,),
)
@@ -1080,9 +1097,9 @@ class PostgresPortfolioRepository:
updated_at = NOW()
WHERE portfolio_id = %s
RETURNING
portfolio_id, broker, status, symbol,
portfolio_id, broker, status, name, symbol,
cash_balance, asset_quantity, asset_price, profit_buffer,
active_strategy_id, avabile_strategies, created_at, updated_at, last_trade_at
active_strategy_id, avabile_strategies, owner_user_id, created_at, updated_at, last_trade_at
""",
(updated_buffer, portfolio_id),
)
@@ -1149,9 +1166,9 @@ class PostgresPortfolioRepository:
updated_at = NOW()
WHERE portfolio_id = %s
RETURNING
portfolio_id, broker, status, symbol,
portfolio_id, broker, status, name, symbol,
cash_balance, asset_quantity, asset_price, profit_buffer,
active_strategy_id, avabile_strategies, created_at, updated_at, last_trade_at
active_strategy_id, avabile_strategies, owner_user_id, created_at, updated_at, last_trade_at
""",
(cash, buf, portfolio_id),
)