Skip to content

feat: Taste Fingerprint — personal collection analytics and shareable taste card#120

Merged
SimplicityGuy merged 11 commits intomainfrom
feat/taste-fingerprint-114
Mar 14, 2026
Merged

feat: Taste Fingerprint — personal collection analytics and shareable taste card#120
SimplicityGuy merged 11 commits intomainfrom
feat/taste-fingerprint-114

Conversation

@SimplicityGuy
Copy link
Copy Markdown
Owner

Summary

  • Adds 4 new API endpoints under /api/user/taste/ for personal collection analytics (feat: Taste Fingerprint — personal collection analytics and shareable taste card #114)
    • GET /api/user/taste/fingerprint — full analytics object (heatmap, obscurity, taste drift, top labels, peak decade)
    • GET /api/user/taste/heatmap — genre × decade cross-tabulation matrix
    • GET /api/user/taste/blindspots?limit=5 — recommended underexplored genres/decades based on artist overlap
    • GET /api/user/taste/card — shareable SVG taste card (≤100KB, server-side generated)
  • Obscurity score: platform-internal metric based on how many other users collected each release (1 - collectors/max_collectors)
  • All endpoints require JWT auth and minimum 10 synced collection items (422 if below)
  • Uses asyncio.gather() for concurrent Neo4j queries in fingerprint and card endpoints
  • SVG card uses html.escape() for XSS prevention with clamped bar widths
  • 39 new tests, all passing; mypy and ruff clean

New Files

  • api/queries/taste_queries.py — 6 Neo4j Cypher query functions
  • api/routers/taste.py — FastAPI router with 4 endpoints
  • api/taste_card.py — SVG taste card generator
  • tests/api/test_taste_queries.py — query unit tests
  • tests/api/test_taste.py — endpoint tests
  • tests/api/test_taste_card.py — SVG generation tests

Modified Files

  • api/models.py — 6 new Pydantic response models
  • api/api.py — taste router registration
  • tests/api/conftest.py — taste router in test fixture

Test plan

  • All 39 new taste tests pass
  • Full API test suite passes (no regressions)
  • mypy clean
  • ruff clean
  • Pre-commit hooks pass
  • Manual verification with a synced collection (≥10 items)
  • SVG card renders correctly in browser

Closes #114

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@SimplicityGuy SimplicityGuy force-pushed the main branch 2 times, most recently from c785f85 to 6a5a997 Compare March 13, 2026 22:28
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 97.53086% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
api/routers/taste.py 94.59% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

SimplicityGuy and others added 4 commits March 13, 2026 19:43
Add HeatmapCell, HeatmapResponse, ObscurityScore, TasteDriftYear,
BlindSpot, and FingerprintResponse models to support the taste
fingerprint feature.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… blind spots, top labels (#114)

Add api/queries/taste_queries.py with get_collection_count,
get_taste_heatmap, get_obscurity_score, get_taste_drift,
get_blind_spots, and get_top_labels Neo4j queries.
Add comprehensive tests covering all query functions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…indspots, and card endpoints (#114)

Create api/routers/taste.py with 4 endpoints using asyncio.gather()
for concurrent queries. Includes _MIN_COLLECTION_ITEMS=10 guard,
_peak_decade() helper, and configure() function.
Register router in api/api.py and tests/api/conftest.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create api/taste_card.py with render_taste_card() producing a 600x400
SVG. Uses html.escape() for XSS prevention and clamps bar width to
max(4, min(200, int(obscurity_score * 200))).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@SimplicityGuy SimplicityGuy force-pushed the feat/taste-fingerprint-114 branch from 5a33029 to bce4330 Compare March 14, 2026 02:43
SimplicityGuy and others added 6 commits March 13, 2026 19:59
Tests were written against a different schema than what was implemented.
Updated all 5 failing tests to match the actual field names and types
in HeatmapResponse, ObscurityScore, TasteDriftYear, BlindSpot, and
FingerprintResponse models.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep both PathNode/PathResponse models from main and Taste Fingerprint
models from this branch, ordering Path models first.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move endpoints from /api/taste/ to /api/user/taste/ for namespace
  consistency with other user-scoped endpoints
- Expose limit query param on blindspots endpoint (default 5, max 20)
- Use asyncio.gather() inside get_taste_heatmap and get_obscurity_score
  for concurrent sub-queries
- Add Cache-Control: no-store header to SVG card response
- Add tests for limit parameter passthrough and cache header

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

E2E Coverage (firefox)

Totals Coverage
Statements: 34.91% ( 693 / 1985 )
Lines: 34.91% ( 693 / 1985 )

StandWithUkraine

@github-actions
Copy link
Copy Markdown
Contributor

E2E Coverage (webkit)

Totals Coverage
Statements: 34.91% ( 693 / 1985 )
Lines: 34.91% ( 693 / 1985 )

StandWithUkraine

@github-actions
Copy link
Copy Markdown
Contributor

E2E Coverage (chromium)

Totals Coverage
Statements: 34.91% ( 693 / 1985 )
Lines: 34.91% ( 693 / 1985 )

StandWithUkraine

@github-actions
Copy link
Copy Markdown
Contributor

E2E Coverage (webkit - iPhone 15)

Totals Coverage
Statements: 34.91% ( 693 / 1985 )
Lines: 34.91% ( 693 / 1985 )

StandWithUkraine

@github-actions
Copy link
Copy Markdown
Contributor

E2E Coverage (webkit - iPad Pro 11)

Totals Coverage
Statements: 34.91% ( 693 / 1985 )
Lines: 34.91% ( 693 / 1985 )

StandWithUkraine

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.

feat: Taste Fingerprint — personal collection analytics and shareable taste card

1 participant