AstroBaaS

Reviews & social proof

Rating Display Component

Free — GPL coresize Splanned, not built

Generated from docs/plan/core/rating-display-component/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.

A storefront component that displays the aggregate review rating (e.g., ‘4.2★ 127 reviews’) on product cards and details. Core provides the computation logic, caching, and accessible star rendering; merchants get the trust signal without a paid add-on.

The problem

Reviews exist in the system, but customers browsing don’t see any rating signal on product cards or listings. Without visible proof that others have purchased and rated a product, they hesitate to buy. Merchants lose a critical trust lever.

What it does

  • Compute aggregate star rating (average of all approved reviews)
  • Compute review count (approved reviews only)
  • Cache aggregate stats to avoid recomputation on every storefront request
  • Render accessible star display: <span role="img" aria-label="4.2 out of 5 stars"> with visual stars
  • Show review count badge alongside rating
  • Handle no-reviews state gracefully (e.g., ‘Be the first to review’)
  • Support multiple display modes: full stars, numeric badge, compact text
  • Invalidate cache when a review is published, rejected, or deleted
  • Provide rating breakdown (count of 5-star, 4-star, 3-star, etc.) for rich snippets
  • Work correctly across all storage drivers without backend-specific queries

What it deliberately does NOT do

Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.

  • Review sorting or filtering (that belongs with the review list component, not the rating display)
  • Filtering products by star rating in catalog (that’s a storefront search/filter feature)
  • Seller or merchant ratings (only product-level reviews in scope)
  • Review pagination or infinite scroll (handled by review list component)
  • Internationalization of text like ‘reviews’ (handled by i18n layer, not this component)

Data model

Add cached review_stats computed object to product record: { avgRating: float, count: int, breakdown: { 5: int, 4: int, 3: int, 2: int, 1: int } }. Can be computed on-demand or stored in a denormalized cache table. No migration required; compute from review data at deploy time.

API

  • GET /storefront/products/:id/review-stats — returns { avgRating: 4.2, count: 127, breakdown: {5: 60, 4: 40, 3: 20, 2: 5, 1: 2} }
  • Internal: POST /admin/reviews/:id/publish — triggers cache invalidation for product
  • Internal: POST /admin/reviews/:id/reject — triggers cache invalidation
  • Internal: DELETE /admin/reviews/:id — triggers cache invalidation
  • Internal (cache rebuild): POST /admin/products/:id/rebuild-review-stats — manual cache refresh

Every route added here must also appear in src/pages/openapi.json.ts — a test fails the build if it does not.

Admin

Review stats widget on product details showing: average rating, total count, breakdown chart. Bulk action: ‘Rebuild all review stats’ for cache refresh after migrations. Debug button to invalidate stats for one product.

The seam — why this is core

Core owns rating computation (averaging, count), cache invalidation logic, and storefront display component. No external service or credential; pure derived data from reviews already in the system.

Core owns the interface + honest rating renderer; storefront components are infrastructure, not a credential or support commitment.

Dependencies

  • Review system must exist with moderation state (status field)
  • Review publication must trigger webhook or event for cache invalidation
  • Cache layer (in-memory, Redis, or lowdb KV) must exist or be added
  • Storefront component rendering capability (Astro components or template system)

Acceptance checks

Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.

  • GET /storefront/products/:id/review-stats returns avgRating between 1.0 and 5.0 inclusive
  • avgRating is computed as: sum of all ratings / count of approved reviews, rounded to 1 decimal
  • count includes only reviews where status=‘published’ and moderated=true
  • Cache is invalidated and recomputed within 2 seconds of publishing a review
  • breakdown object sums to count: breakdown[5] + breakdown[4] + … + breakdown[1] === count
  • Star component renders without errors when avgRating is 0, 1, 3.5, 5, or null
  • Removing a review decreases count and recalculates avgRating correctly
  • Component has aria-label: ‘4.2 out of 5 stars, based on 127 reviews’ for accessibility

Risks

Cache not invalidated = stale ratings shown to customers for hours. avgRating computed wrong (e.g., dividing by total reviews instead of approved). Cache stampede if 100 reviews published in rapid succession. Rating not added to OpenAPI schema = external tests fail.

Commercial context

Suggested pricefree (core)
Rival anchorShopify: included (theme components); Magento: included

The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.


Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full catalogue and ../../AI-GUIDE.md for how to work on this repository.