chore: restructure SRS for asset catalog and tag model redesign (dcy-001/002, REQ-001~008)
Architecture Redesign (May 19, 2026): - Separate admin-managed asset catalog from user portfolios - Eliminate portfolio as asset definition; clarify portfolio as user position - Introduce new asset_catalog + portfolio structure Discovery Documents: - dcy-001: asset-catalog-and-user-portfolio-model — admin asset management and user portfolio separation - dcy-002: tag-ownership-and-applicability-policy — tag model implementation strategy New Requirements (REQ-001~008): - REQ-001: tags master table introduction (Data, Proposed) - REQ-002: assets.tag_ids UUID[] column addition (Data, Proposed) - REQ-003: portfolios.tag_ids and portfolio_tags removal (Data, Proposed) - REQ-004: tags master HTTP API (Interface, Proposed) - REQ-005: tag apply/remove HTTP API (Interface, Proposed) - REQ-006: portfolio_tags data migration (Migration, Proposed) - REQ-007: pfhub tag CLI commands (Interface, Proposed) - REQ-008: tag model baseline docs update (Documentation, Proposed) Cleanup: - Remove archived SRS documents (REQ-001~029 old structure) - Remove archived batch documentation (BAT-001~010) - Remove archived discovery documents (dcy-001~006 old structure) - Remove archived release documentation (REL-001~006) Data Model Updates: - Add Deployment category to SRS structure - Add Data category for new data model requirements - Update app/cli/core/utils.py for new tag handling Documentation: - Create new SRS index with consolidated requirement structure - Update docs/discovery/index.md with new discovery references - Migrate from requirement-centric to domain-model-centric organization Rationale: - Existing single-portfolio model lacks admin catalog governance - New asset catalog enables central management of tradeable symbols - Tag system supports user-driven asset organization and discovery - Cleaner separation of concerns between admin operations and user trading
This commit is contained in:
+10
-16
@@ -121,22 +121,16 @@ def print_portfolio_detail(console: Console, detail: PortfolioDetailResponse) ->
|
||||
console.print(ledger_table)
|
||||
|
||||
|
||||
def print_user_table(console: Console, users: list[UserResponse]) -> None:
|
||||
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",
|
||||
def print_user_list(console: Console, users: list[UserResponse]) -> None:
|
||||
for i, user in enumerate(users):
|
||||
if i:
|
||||
console.print()
|
||||
console.print(f"[bold]{user.username}[/bold] [dim]{user.id}[/dim]")
|
||||
console.print(f" email {user.email or 'N/A'}")
|
||||
console.print(
|
||||
f" created {user.created_at.isoformat(timespec='seconds') if user.created_at else 'N/A'}"
|
||||
f" updated {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:
|
||||
@@ -274,7 +268,7 @@ def render_output(console: Console, output_format: str, payload: Any, *, empty_m
|
||||
print_portfolio_list(console, payload)
|
||||
return
|
||||
if all(isinstance(item, UserResponse) for item in payload):
|
||||
print_user_table(console, payload)
|
||||
print_user_list(console, payload)
|
||||
return
|
||||
if all(isinstance(item, CommentResponse) for item in payload):
|
||||
print_comment_table(console, payload)
|
||||
|
||||
Reference in New Issue
Block a user