fix: blank company charts + competitor GUIDs instead of tickers

Trend charts blank:
- trend_windows uses upsert (1 row per ticker/window), so charts had
  at most 1 data point. Added trend_history table (migration 024) that
  appends every snapshot. New /api/trends/history endpoint serves the
  time series. Frontend now uses useTrendHistory for charts and
  useTrends for the latest summary card.

Competitor GUIDs:
- list_competitors query returned raw company_b_id UUIDs without
  joining companies table. Added LEFT JOIN with CASE to resolve the
  other company's ticker and legal_name. Updated Pydantic model to
  include enriched fields. Frontend fallback changed from truncated
  UUID to ticker/legal_name/Unknown.
This commit is contained in:
Celes Renata
2026-04-17 00:42:55 +00:00
parent f2d8744a4f
commit 7c589353f8
6 changed files with 169 additions and 16 deletions
+22 -6
View File
@@ -53,6 +53,9 @@ class CompetitorRelationship(BaseModel):
active: bool
created_at: datetime
updated_at: datetime
# Enriched from companies table
ticker: str | None = None
legal_name: str | None = None
def _row_dict(row: asyncpg.Record) -> dict[str, Any]:
@@ -128,18 +131,31 @@ async def create_competitor(company_id: str, body: CompetitorRelationshipCreate,
@router.get("/companies/{company_id}/competitors", response_model=List[CompetitorRelationship])
async def list_competitors(company_id: str, request: Request):
"""List active competitor relationships for a company, ordered by strength descending."""
"""List active competitor relationships for a company, ordered by strength descending.
Enriches each relationship with the ticker and legal_name of the
*other* company (the one that isn't company_id).
"""
pool = _get_pool(request)
if not await _company_exists(pool, company_id):
raise HTTPException(404, "Company not found")
rows = await pool.fetch(
"""SELECT id, company_a_id, company_b_id, relationship_type, strength,
bidirectional, source, active, created_at, updated_at
FROM competitor_relationships
WHERE (company_a_id = $1 OR company_b_id = $1) AND active = TRUE
ORDER BY strength DESC""",
"""SELECT cr.id, cr.company_a_id, cr.company_b_id,
cr.relationship_type, cr.strength,
cr.bidirectional, cr.source, cr.active,
cr.created_at, cr.updated_at,
c.ticker, c.legal_name
FROM competitor_relationships cr
LEFT JOIN companies c
ON c.id = CASE
WHEN cr.company_a_id = $1 THEN cr.company_b_id
ELSE cr.company_a_id
END
WHERE (cr.company_a_id = $1 OR cr.company_b_id = $1)
AND cr.active = TRUE
ORDER BY cr.strength DESC""",
company_id,
)
return [_row_dict(r) for r in rows]