Brewhaus
An AI-driven specialty coffee marketplace for home enthusiasts.
The Problem
Home coffee enthusiasts struggle to find beans matched to their taste. Brewhaus profiles flavor with AI and recommends roasts that fit each palate — turning discovery into an interactive experience.
My Role
Built solo with AI-assisted development — SSR storefront, vector search, AI integration, and Dockerized deployment.
Highlights
- Next.js 15 SSR storefront with gamification and subscription billing
- pgvector semantic search powering AI-driven flavor profiling
- Claude AI integration for personalized recommendations
- Containerized with Docker and served via Cloudflare Tunnels
Stack
Constraints
- Self-hosted on a home server — no cloud bill, but also no auto-scaling.
- Solo build, so the stack had to favour boring, well-documented pieces over novelty.
- AI cost must stay bounded — recommendations had to use embeddings, not a per-request LLM call.
System Architecture
Key Trade-offs
The decisions worth defending — what I chose, what I turned down, and why.
Recommendation engine
Chose
pgvector similarity on cached embeddings
Rejected
LLM call per recommendation
Vector search is millisecond-fast and effectively free once embeddings are computed; LLMs would have added cost and latency per page view.
Public ingress
Chose
Cloudflare Tunnel
Rejected
Public VPS with open ports
No exposed origin IP, free TLS, and DDoS protection inherited from Cloudflare — much smaller attack surface for a self-hosted box.
Rendering model
Chose
Next.js 15 SSR
Rejected
Pure client-rendered SPA
Product pages need to be indexable and shareable; SSR gives fast first paint and clean OG cards without a separate prerender step.
What I'd Do Differently
An honest retrospective — the stuff I'd change with more time, more users, or a second pass.
- 1Move embedding generation to a background queue — synchronous calls during admin product writes briefly blocked the UI.
- 2Add a staging container that mirrors prod data shape so AI tuning doesn't happen against the live DB.
- 3Track recommendation quality with a click-through metric instead of relying on subjective spot-checks.
Technical Deep-Dive
Architecture, specifications, and implementation details.
10 · Testing Strategy
#Coverage Targets
| Layer | Tool | Target Coverage |
|---|---|---|
| Unit (lib/) | Vitest | > 80% |
| Integration | Vitest | > 60% |
| E2E | Playwright | Critical paths |
| API (tRPC) | Vitest + MSW | > 70% |
| Performance | Lighthouse CI | LCP < 200ms |
#Test Structure
__tests__/
├── unit/
│ ├── xp.test.ts — XP calculation, level logic
│ ├── quiz.test.ts — Quiz processing, profile building
│ ├── recommendations.test.ts — Vector search, re-ranking
│ └── stripe.test.ts — Subscription plan config
│
├── integration/
│ ├── products.router.test.ts — tRPC products router
│ ├── quiz.router.test.ts — tRPC quiz router
│ └── webhooks.test.ts — Stripe webhook handling
│
└── e2e/
├── homepage.spec.ts — Hero, products, AI widget
├── quiz.spec.ts — Full quiz flow, XP award
├── shop.spec.ts — Browse, filter, add to cart
├── checkout.spec.ts — Cart → Stripe checkout
└── profile.spec.ts — XP dashboard, badges
#Critical E2E Paths
1. QUIZ FLOW
/ → click "Start Quiz" → complete 5 questions
→ see recommendations → add to cart → see XP toast
2. PURCHASE FLOW
/shop → click product → add to bag
→ cart sidebar → checkout → Stripe test card
→ order confirmation → XP awarded
3. SUBSCRIPTION FLOW
/subscribe → click Connoisseur → Stripe checkout
→ return to profile → subscription badge shown
→ XP bonus visible in history
4. AUTH FLOW
→ Google OAuth → redirect back to site
→ Profile page shows correct user data
#Running Tests
# Unit and integration
npm run test
# E2E (requires dev server running)
npm run test:e2e
# Coverage report
npm run test:coverage
# Type checking
npm run typecheck
#CI/CD Test Gates
# On every PR:
1. npm run typecheck — zero TypeScript errors
2. npm run lint — zero ESLint errors
3. npm run test — all unit/integration pass
4. npm run build — successful Next.js build
# On merge to main:
5. docker compose build — successful image build
6. npm run test:e2e — all critical paths pass
7. Lighthouse CI — LCP < 200ms, score > 90
End of documentation. See scripts/ for deployment automation.