A Rotten Tomatoes-style aggregation hub for board games — critic consensus scores, community reviews, personalized taste matching, and discovery, all in one place.
| Feature | Description |
|---|---|
| 🏠 Landing Page | Hero section, trending games, latest critic reviews, rising games, awards tracker, and newsletter signup |
| 🎮 Game Pages | Dual GamePulse scores (critics + community), consensus badge, full critic breakdown, community reviews, price comparison, and similar games |
| 🔍 Browse & Discover | Filter by category, player count, and complexity. Sort by score, trending, newest, or most reviewed. Search autocomplete with keyboard navigation |
| 👤 Critic Profiles | Taste profile radar charts, review history, taste match percentage, and follow/unfollow actions |
| 📊 User Dashboard | Your ratings, watchlist, wishlist, matched critics, taste profile visualization, and personalized score predictions |
| 📰 Content Feed | Personalized feed with filters (reviews, news, deals, videos), release calendar, and weekly newsletter preview |
| 🧮 Taste Matching | Cosine similarity + Pearson correlation across 6 taste dimensions to match users with aligned critics |
| 💾 Local Persistence | All interactions (ratings, reviews, watchlist, follows, newsletter signups) persist in SQLite |
# 1. Clone and install
git clone <your-repo-url>
cd 10-gamepulse
npm install
# 2. Start the development server
npm run dev
# 3. Open in your browser
open http://localhost:3000The database seeds automatically on first run with 60+ board games, 14 named critic profiles, 50+ community users, 200+ critic reviews, rich watchlists/wishlists, awards, and release-calendar data. No extra setup is required in local development.
| Script | Description |
|---|---|
npm run dev |
Start the Next.js development server |
npm run build |
Create an optimized production build |
npm run start |
Serve the production build |
npm run lint |
Run ESLint checks |
npm run type-check |
Run TypeScript compiler checks (no emit) |
npm run check |
Run type-check → lint → build (CI gate) |
npm run clean |
Remove build artifacts and database |
┌─────────────────────────────────────────────────────┐
│ Next.js App Router │
│ ┌──────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ │
│ │ / │ │ /browse │ │ /feed │ │ /critics │ │
│ │ /games │ │ /me │ │ │ │ │ │
│ └────┬─────┘ └────┬─────┘ └───┬────┘ └────┬─────┘ │
│ └─────────────┴───────────┴───────────┘ │
│ │ │
│ ┌─────────────────────▼──────────────────────────┐ │
│ │ lib/queries/ (Data Layer) │ │
│ │ games.ts · critics.ts · feed.ts · dashboard.ts│ │
│ └─────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌─────────────────────▼──────────────────────────┐ │
│ │ lib/scoring.ts + lib/taste.ts │ │
│ │ Cosine similarity · Pearson correlation │ │
│ │ Consensus badges · Personalized predictions │ │
│ └─────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌─────────────────────▼──────────────────────────┐ │
│ │ lib/db/ (SQLite via better-sqlite3) │ │
│ │ connection.ts · schema.ts · seed.ts · seeds/ │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
10-gamepulse/
├── app/ # Next.js App Router pages
│ ├── page.tsx # Landing page
│ ├── api/health/ # Health check endpoint
│ ├── browse/ # Browse & discover with filters
│ ├── critics/ # Critic directory + [slug] profiles
│ ├── feed/ # Personalized content feed
│ ├── games/[slug]/ # Individual game pages
│ ├── me/ # User dashboard
│ ├── newsletter/manage/ # Self-serve newsletter removal page
│ ├── robots.ts # SEO robots.txt generation
│ └── sitemap.ts # SEO sitemap generation
├── components/ # React components
│ ├── gamepulse-ui.tsx # Shared UI: cards, badges, sections
│ ├── search-autocomplete.tsx # Header search combobox
│ ├── client-widgets.tsx # Client chart widgets
│ ├── action-forms.tsx # Form components with server actions
│ ├── submit-button.tsx # Pending-state submit button
│ └── toast.tsx # Toast notification system
├── lib/ # Business logic & data access
│ ├── db/ # Database connection, schema, seeds
│ ├── queries/ # Per-domain query modules
│ ├── actions.ts # Server Actions (review, follow, etc.)
│ ├── config.ts # Centralized configuration constants
│ ├── scoring.ts # Score algorithms & consensus logic
│ ├── taste.ts # Taste dimension types
│ └── gamepulse.ts # Barrel re-exports
├── data/ # SQLite database (auto-generated)
├── docs/ # Project documentation
│ ├── PRD.md # Product Requirements Document
│ ├── CODE_REVIEW.md # Code quality audit
│ ├── UX_REVIEW.md # UX & accessibility audit
│ └── IMPROVEMENTS.md # Improvement roadmap
├── .github/ # GitHub templates and CI
│ ├── workflows/ci.yml # CI pipeline
│ ├── ISSUE_TEMPLATE/ # Bug report & feature request forms
│ └── pull_request_template.md
└── public/ # Static assets
GamePulse uses a multi-signal scoring system:
- Critics Score — Weighted average of critic reviews (0–100 scale)
- Community Score — Average of user ratings (1–10 scale, displayed as 0–100)
- Consensus Badge — Derived from score spread and momentum:
- 🏆 Critically Acclaimed — Critics ≥86 AND Community ≥80
- ❤️ Community Favorite — Community ≥88
- 💎 Hidden Gem — Community ≥80, Critics ≥74, Rising ≥60
- 🔥 On the Rise — Default for active games
- ⚡ Divisive — |Critics − Community| ≥15
- Personalized Predictions — Weighted by taste-matched critic correlation (cosine similarity + Pearson)
- The database lives at
data/gamepulse.dband is auto-created on first run - The seed catalog currently includes 60+ games, 14 critics, 50+ users, 200+ critic reviews, 100+ community reviews, awards, release-calendar entries, follow relationships, and saved-list activity
- Seeds are deterministic and transactional: the seeding pass clears and rebuilds reference data in a single SQLite transaction, resets autoincrement sequences, and stamps
app_meta.seed_version - Edge cases are intentionally included, including one-review games, hidden gems, and divisive titles with strong critic / weak community splits
- In production, automatic reseeds are blocked when reference data already exists unless
GAMEPULSE_ENABLE_PRODUCTION_RESEED=1is set - To force a fresh local dataset, run
npm run cleanand then start the app or runnpm run build - The current user is a hardcoded mock user ("alex") — see CONTRIBUTING.md for auth notes
# Build the container
docker build -t gamepulse .
# Run it
docker run -p 3000:3000 gamepulseThe SQLite database is created inside the container at /app/data/gamepulse.db. Mount a volume to persist data across restarts:
docker run -p 3000:3000 -v gamepulse-data:/app/data gamepulseCopy .env.example to .env.local to customize settings:
cp .env.example .env.local| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_BASE_URL |
https://gamepulse.example.com |
Public URL for sitemap, OG tags, canonical links |
NODE_ENV |
development |
Node.js environment |
| Layer | Technology | Why |
|---|---|---|
| Framework | Next.js 16 (App Router) | Server components, server actions, streaming |
| UI | React 19 | Latest concurrent features, useActionState |
| Styling | Tailwind CSS 4 | Utility-first, zero-config with PostCSS |
| Charts | Recharts | Composable radar charts for taste profiles |
| Icons | Lucide React | Tree-shakeable icon library |
| Database | better-sqlite3 | Synchronous SQLite for server components |
| Language | TypeScript 5 | Strict mode enabled |
See CONTRIBUTING.md for setup instructions, coding conventions, and the PR process.
MIT