refactor: simplify data model by removing unused fields and constraints

- Remove runtime_id from AuthToken model
- Remove market field from Portfolio model
- Remove BrokerCredential and LedgerTrade unused models
- Remove unique constraint on (owner_user_id, name)
- Simplify postgres repository schema and queries
- Clean up auth_service implementation
- Update test suite for simplified model
This commit is contained in:
2026-05-13 06:48:26 +00:00
parent 03bc3dcd8f
commit 3255d096f1
6 changed files with 149 additions and 980 deletions
+72 -74
View File
@@ -39,22 +39,29 @@ def to_plain_data(value: Any) -> Any:
def print_portfolio_table(console: Console, portfolios: list[PortfolioListItem]) -> None:
for i, item in enumerate(portfolios):
if i > 0:
console.print()
lines = [
f"id: {item.portfolio_id}",
f"broker: {item.broker}",
f"status: {item.status}",
f"symbol: {item.symbol}",
f"cash: {format_currency(item.cash_balance)}",
f"qty: {item.asset_quantity:g}",
f"price: {format_currency(item.price)}",
f"buffer: {format_currency(item.profit_buffer)}",
f"total: {format_currency(item.total_value)}",
]
for line in lines:
console.print(line)
table = Table(title="Portfolios", expand=True)
table.add_column("ID", style="cyan", no_wrap=True)
table.add_column("Broker")
table.add_column("Status", no_wrap=True)
table.add_column("Symbol", no_wrap=True)
table.add_column("Cash", justify="right")
table.add_column("Qty", justify="right")
table.add_column("Price", justify="right")
table.add_column("Buffer", justify="right")
table.add_column("Total", justify="right")
for item in portfolios:
table.add_row(
item.portfolio_id,
item.broker,
item.status,
item.symbol,
format_currency(item.cash_balance),
f"{item.asset_quantity:g}",
format_currency(item.price),
format_currency(item.profit_buffer),
format_currency(item.total_value),
)
console.print(table)
def print_portfolio_detail(console: Console, detail: PortfolioDetailResponse) -> None:
@@ -122,69 +129,60 @@ def print_portfolio_detail(console: Console, detail: PortfolioDetailResponse) ->
def print_user_table(console: Console, users: list[UserResponse]) -> None:
for i, user in enumerate(users, 1):
lines = [
f"username: {user.username}",
f"id: {user.id}",
f"email: {user.email or 'N/A'}",
f"permission: {user.permission}",
f"is_active: {'true' if user.is_active else 'false'}",
f"created_at: {user.created_at.isoformat(timespec='seconds') if user.created_at else 'N/A'}",
f"updated_at: {user.updated_at.isoformat(timespec='seconds') if user.updated_at else 'N/A'}",
]
for line in lines:
console.print(line)
if i < len(users):
console.print()
table = Table(title="Users", expand=True)
table.add_column("ID", style="cyan", no_wrap=True)
table.add_column("Username", no_wrap=True)
table.add_column("Email")
table.add_column("Created At", no_wrap=True)
table.add_column("Updated At", no_wrap=True)
for user in users:
table.add_row(
user.id,
user.username,
user.email or "N/A",
user.created_at.isoformat(timespec="seconds") if user.created_at else "N/A",
user.updated_at.isoformat(timespec="seconds") if user.updated_at else "N/A",
)
console.print(table)
def print_user_detail(console: Console, user: UserResponse) -> None:
lines = [
f"id: {user.id}",
f"username: {user.username}",
f"email: {user.email or 'N/A'}",
f"permission: {user.permission}",
f"is_active: {'true' if user.is_active else 'false'}",
f"last_login_at: {user.last_login_at.isoformat(timespec='seconds') if user.last_login_at else 'N/A'}",
f"created_at: {user.created_at.isoformat(timespec='seconds') if user.created_at else 'N/A'}",
f"updated_at: {user.updated_at.isoformat(timespec='seconds') if user.updated_at else 'N/A'}",
]
service_token_count = getattr(user, "service_token_count", None)
service_token_names = getattr(user, "service_token_names", None)
if service_token_count is not None and service_token_names is not None:
rendered_names = ", ".join(service_token_names) if service_token_names else "N/A"
lines.append(f"service_token_count: {service_token_count}")
lines.append(f"service_token_names: {rendered_names}")
for line in lines:
console.print(line)
console.print(
Panel.fit(
"\n".join(
[
f"id: {user.id}",
f"username: {user.username}",
f"email: {user.email or 'N/A'}",
f"created_at: {user.created_at.isoformat(timespec='seconds') if user.created_at else 'N/A'}",
f"updated_at: {user.updated_at.isoformat(timespec='seconds') if user.updated_at else 'N/A'}",
]
),
title="User",
)
)
def print_service_token_list(console: Console, tokens: list[AuthTokenResponse]) -> None:
for i, token in enumerate(tokens, 1):
status = "[red]revoked[/red]" if token.revoked_at else "[green]active[/green]"
expires = token.expires_at.isoformat(timespec="seconds") if token.expires_at else "never"
last_used = token.last_used_at.isoformat(timespec="seconds") if token.last_used_at else "-"
revoked_at = token.revoked_at.isoformat(timespec="seconds") if token.revoked_at else "-"
created_at = token.created_at.isoformat(timespec="seconds") if token.created_at else "N/A"
lines = [
f"[bold cyan]{token.name}[/bold cyan] ({status})",
f" token_prefix: {token.token_prefix} [dim](full token shown only at issue time)[/dim]",
f" id : {token.id}",
f" user_id : {token.user_id}",
f" perm : {token.permission}",
f" expires : {expires}",
f" last_used: {last_used}",
f" created : {created_at}",
]
if token.revoked_at:
lines.append(f" revoked : {revoked_at}")
console.print("\n".join(lines))
if i < len(tokens):
console.print("[dim]─[/dim]" * 40)
# Keep old name as alias for backward compatibility
print_service_token_table = print_service_token_list
def print_service_token_table(console: Console, tokens: list[AuthTokenResponse]) -> None:
table = Table(title="Service Tokens", expand=True)
table.add_column("Name", style="cyan", no_wrap=True)
table.add_column("Permission", no_wrap=True)
table.add_column("User ID", no_wrap=True)
table.add_column("Prefix", no_wrap=True)
table.add_column("Expires At", no_wrap=True)
table.add_column("Revoked At", no_wrap=True)
table.add_column("Created At", no_wrap=True)
for token in tokens:
table.add_row(
token.name,
token.permission,
token.user_id,
token.token_prefix,
token.expires_at.isoformat(timespec="seconds") if token.expires_at else "never",
token.revoked_at.isoformat(timespec="seconds") if token.revoked_at else "-",
token.created_at.isoformat(timespec="seconds") if token.created_at else "N/A",
)
console.print(table)
def print_comment_table(console: Console, comments: list[CommentResponse]) -> None: