Skip to content

feat: insights pages — stats, plot of the day, similar specs#5233

Merged
MarkusNeusinger merged 3 commits intomainfrom
feature/insights-pages
Apr 7, 2026
Merged

feat: insights pages — stats, plot of the day, similar specs#5233
MarkusNeusinger merged 3 commits intomainfrom
feature/insights-pages

Conversation

@MarkusNeusinger
Copy link
Copy Markdown
Owner

Summary

  • Stats Dashboard (/stats): Library quality/LOC histograms, coverage dot matrix, top rated implementations, tag cloud, timeline, Plausible analytics link
  • Plot of the Day: Daily featured high-quality implementation on homepage (dismissable, sessionStorage persisted)
  • Similar Specifications/Implementations: Tag-based Jaccard similarity — spec pages use spec tags, impl pages use spec + impl tags, with hover-highlighting of shared tags
  • Deferred code loading: Heavy DB fields (code, review_criteria_checklist, review_image_description, tested) deferred in model (~25MB saved per get_all()), new lightweight /specs/{id}/{lib}/code endpoint, frontend prefetch on impl page open
  • Collapsible spec tabs with always-visible tags and metadata footer showing updated dates
  • New insights API router (/insights/dashboard, /insights/plot-of-the-day, /insights/related/{spec_id})
  • Updated sitemap, Plausible docs, API docs, footer links

Closes #5228
Closes #5229
Closes #5230

Test plan

  • Verify /stats page loads with all sections (counters, library histograms, coverage matrix, top rated, timeline, tags)
  • Verify Plot of the Day appears on homepage when no filters active, dismiss persists across navigation
  • Verify similar specifications on spec overview page (spec tags only, links to specs)
  • Verify similar implementations on impl detail page (spec + impl tags, links to impls, same library preferred)
  • Verify tag hover highlighting works between similar cards and tag chips
  • Verify code tab loads lazily (check network tab — no code in /specs/{id} response)
  • Verify all tabs collapse/expand on click including re-click to close
  • Run uv run pytest tests/unit — 1068 tests pass
  • Run yarn lint && yarn build — 0 errors

🤖 Generated with Claude Code

…specs

New features that leverage the database more heavily:

- Stats page (/stats): library quality/LOC histograms, coverage dot matrix,
  top rated implementations, tag cloud, timeline, plausible link
- Plot of the Day: daily featured high-quality impl on homepage, dismissable
- Similar specifications/implementations: tag-based Jaccard similarity on
  spec pages (spec tags) and impl pages (spec + impl tags), with hover
  highlighting of shared tags
- Lazy code loading: code field deferred in DB model (~25MB saved per
  get_all), new /specs/{id}/{lib}/code endpoint, frontend prefetch
- Collapsible spec tabs with always-visible tags and metadata footer
- New insights API router with /dashboard, /plot-of-the-day, /related
- Updated sitemap, plausible docs, API docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 7, 2026 21:22
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 7, 2026

Codecov Report

❌ Patch coverage is 89.50820% with 32 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
api/routers/insights.py 90.53% 25 Missing ⚠️
core/database/repositories.py 56.25% 7 Missing ⚠️

📢 Thoughts on this report? Let us know!

Covers dashboard, plot-of-the-day, related specs (spec/full modes),
code lazy-loading endpoint with cache hit/miss/404 scenarios.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds “Insights” features across the API and React app (public stats dashboard, plot-of-the-day, and related specs/impls), while reducing payload sizes by deferring large implementation fields and lazy-loading code.

Changes:

  • Added new Insights API router (/insights/*) and new /specs/{spec_id}/{library}/code endpoint to support stats, plot-of-the-day, and similarity recommendations.
  • Deferred heavyweight Impl fields at the ORM level and updated repositories/endpoints to explicitly undefer/load only when needed.
  • Added frontend pages/components for /stats, Plot of the Day on the homepage, related specs/impls on spec pages, and lazy code fetching.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/unit/api/test_routers.py Updates mocks for repository method rename/addition (get_all_with_code).
docs/reference/plausible.md Documents /stats route + expands analytics destination values.
docs/reference/api.md Documents new Insights endpoints and code endpoint.
core/database/repositories.py Adds get_all_with_code() and LOC aggregation helpers; updates load/defer behavior.
core/database/models.py Defers heavyweight Impl columns (code/review fields/tested).
app/src/types/index.ts Adds updated field to implementation type.
app/src/router.tsx Adds /stats route.
app/src/pages/StatsPage.tsx Implements stats dashboard UI consuming /insights/dashboard.
app/src/pages/SpecPage.tsx Adds related specs/impls UI + prefetch/lazy code loading.
app/src/pages/HomePage.tsx Adds Plot of the Day section on the homepage.
app/src/hooks/useCodeFetch.ts Switches to new lightweight /specs/{spec_id}/{library}/code fetch.
app/src/components/SpecTabs.tsx Makes tabs collapsible, moves tags/metadata footer to always-visible section, supports tag highlighting.
app/src/components/RelatedSpecs.tsx New component to render similarity-based recommendations with hover tag highlighting.
app/src/components/PlotOfTheDay.tsx New component to render daily featured implementation (dismissable).
app/src/components/Footer.tsx Updates stats link to internal /stats route + analytics event name.
api/schemas.py Adds updated to ImplementationResponse.
api/routers/specs.py Removes code from main spec response; adds /specs/{spec_id}/{library}/code.
api/routers/seo.py Adds /stats to sitemap.
api/routers/libraries.py Switches to get_all_with_code() for library image+code endpoint.
api/routers/insights.py New Insights endpoints: dashboard, plot-of-the-day, related specs.
api/routers/init.py Exposes insights_router.
api/main.py Includes insights router + adds cache headers for /insights/*.

Comment thread api/routers/insights.py Outdated
Comment on lines +261 to +262
gen_dt = _parse_iso(impl.generated_at)
if gen_dt:
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_parse_iso() expects an ISO string, but _build_dashboard() passes impl.generated_at which is a datetime ORM field. This will raise at runtime (e.g., datetime has no .replace("Z", ...)), breaking /insights/dashboard timeline aggregation. Use the datetime directly (normalizing tz if needed), or update _parse_iso to accept datetime | str.

Suggested change
gen_dt = _parse_iso(impl.generated_at)
if gen_dt:
gen_dt = impl.generated_at
if gen_dt:
if gen_dt.tzinfo is None:
gen_dt = gen_dt.replace(tzinfo=timezone.utc)

Copilot uses AI. Check for mistakes.
Comment on lines +115 to +127
"""Get a spec by ID with implementations and library info.

Note: Heavy deferred fields (code, review_criteria_checklist) are NOT loaded.
Use ImplRepository.get_by_spec_and_library() for full impl details.
review_image_description IS loaded (small, needed for detail display).
"""
result = await self.session.execute(
select(Spec).where(Spec.id == spec_id).options(selectinload(Spec.impls).selectinload(Impl.library))
select(Spec)
.where(Spec.id == spec_id)
.options(
selectinload(Spec.impls).selectinload(Impl.library),
selectinload(Spec.impls).undefer(Impl.review_image_description).undefer(Impl.review_criteria_checklist),
)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_by_id() docstring says heavy deferred fields like review_criteria_checklist are NOT loaded, but the query explicitly undefer()s Impl.review_criteria_checklist. Either remove the undefer() if the field should stay deferred, or update the docstring/comments to reflect what is actually loaded (and why).

Copilot uses AI. Check for mistakes.
Comment thread api/routers/specs.py
Comment on lines +133 to +152
@router.get("/specs/{spec_id}/{library}/code")
async def get_impl_code(spec_id: str, library: str, db: AsyncSession = Depends(require_db)):
"""
Get implementation code for a specific spec + library.

Lightweight endpoint that loads only the code field (deferred in main query).
"""
key = cache_key("impl_code", spec_id, library)
cached = get_cache(key)
if cached is not None:
return cached

repo = ImplRepository(db)
impl = await repo.get_by_spec_and_library(spec_id, library)

if not impl or not impl.code:
raise_not_found("Implementation code", f"{spec_id}/{library}")

result = {"spec_id": spec_id, "library": library, "code": strip_noqa_comments(impl.code)}
set_cache(key, result)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/specs/{spec_id}/{library}/code is described as a lightweight endpoint that loads only the deferred code field, but it calls ImplRepository.get_by_spec_and_library(), which currently undefer()s additional heavy fields (review image description + criteria checklist). Consider adding a repository method/option that undefer()s only Impl.code for this endpoint to avoid unnecessary DB work and memory usage.

Copilot uses AI. Check for mistakes.
Comment thread api/routers/insights.py
Comment on lines +388 to +402
# Load deferred fields (code, image_description) for just this one impl
full_impl = await impl_repo.get_by_spec_and_library(spec_id, library_id)

return PlotOfTheDayResponse(
spec_id=spec_id,
spec_title=spec_title,
description=description,
library_id=library_id,
library_name=LIBRARY_NAMES.get(library_id, library_id),
quality_score=quality_score,
preview_url=preview_url,
image_description=full_impl.review_image_description if full_impl else None,
code=full_impl.code if full_impl else None,
date=today,
)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlotOfTheDayResponse includes code, but _build_potd() returns the raw full_impl.code without applying strip_noqa_comments() (unlike the other code-returning endpoints). For consistency (and to avoid leaking internal noqa markers), strip/sanitize the code here as well, or remove the code field if the frontend doesn’t use it.

Copilot uses AI. Check for mistakes.
Comment thread api/routers/insights.py Outdated
Comment on lines +4 to +9
Public analytics and discovery features that leverage aggregated database data:
- Dashboard: Rich platform statistics and visualizations
- Plot of the Day: Daily featured high-quality implementation
- Related Plots: Tag-based similarity recommendations
- Library Comparison: Head-to-head library analysis
- Changelog: Recent additions and updates activity feed
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module docstring lists Insights features/endpoints (e.g., library comparison, changelog) that are not implemented in this router. This makes the file-level documentation inaccurate; either remove the unimplemented bullets or add TODOs with issue links.

Suggested change
Public analytics and discovery features that leverage aggregated database data:
- Dashboard: Rich platform statistics and visualizations
- Plot of the Day: Daily featured high-quality implementation
- Related Plots: Tag-based similarity recommendations
- Library Comparison: Head-to-head library analysis
- Changelog: Recent additions and updates activity feed
Public analytics and discovery features implemented in this router:
- Dashboard: Rich platform statistics and visualizations
- Plot of the Day: Daily featured high-quality implementation
- Related Plots: Tag-based similarity recommendations

Copilot uses AI. Check for mistakes.
Comment thread api/routers/insights.py
Comment on lines +336 to +352
@router.get("/dashboard", response_model=DashboardResponse)
async def get_dashboard(db: AsyncSession = Depends(require_db)) -> DashboardResponse:
"""
Get rich platform statistics for the public stats dashboard.

Includes per-library scores, coverage heatmap, top implementations,
tag distribution, score histogram, and implementation timeline.
"""
repo = SpecRepository(db)
impl_repo = ImplRepository(db)

async def _fetch() -> DashboardResponse:
return await _build_dashboard(repo, impl_repo)

return await get_or_set_cache(
cache_key("insights", "dashboard"), _fetch, refresh_after=3600, refresh_factory=_refresh_dashboard
)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New public endpoints were added (/insights/* and /specs/{spec_id}/{library}/code), but there are no unit tests covering their basic behaviors (success path, caching behavior, not-found handling). Please add router tests similar to existing ones in tests/unit/api/test_routers.py to keep coverage consistent with the rest of the API surface.

Copilot generated this review using guidance from repository custom instructions.
…ipping

- Fix _build_dashboard passing datetime to _parse_iso (expects str)
- Add ImplRepository.get_code() that only undefers code field
- Use get_code() in /specs/{id}/{lib}/code endpoint (avoids loading review fields)
- Apply strip_noqa_comments to POTD code response for consistency
- Fix docstring in get_by_id() to match actual undefer behavior
- Remove stale changelog/comparison references from module docstring
- Update tests to use get_code mock

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@MarkusNeusinger MarkusNeusinger merged commit 5d39b7f into main Apr 7, 2026
7 of 10 checks passed
@MarkusNeusinger MarkusNeusinger deleted the feature/insights-pages branch April 7, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Related / Similar Plots Plot of the Day Stats Dashboard Page (/stats)

2 participants