Christopher Mayor 2e138a8364 fix #12: extract session token before dot (Better Auth signed cookie)
Better Auth cookie format is 'token.signature' but DB only stores the
token portion. Split on '.' to extract the actual session token.
2026-04-28 06:56:02 -07:00
2026-04-24 14:06:35 -07:00

ComparAIson

AI-Powered Deep Research Comparison Platform

Compare anything with intelligent, multi-dimensional analysis. ComparAIson uses LLM-powered research to generate comprehensive, visual comparisons — then saves them as shareable posts on your profile.

Features

  • Deep Research Engine — Multi-provider LLM pipeline (Tavily search → Perplexity/OpenAI synthesis) with automatic fallback
  • Interactive Visualizations — Radar charts, grouped bar charts, feature comparison tables, score cards, pros/cons breakdowns
  • Real-Time Streaming — Watch research progress live via Server-Sent Events
  • User Profiles — Save comparisons to your profile, browse a public feed
  • Self-Hosted — Docker Compose deployment, runs on a Raspberry Pi

Tech Stack

Layer Technology
Framework Next.js 15 (App Router, Server Components, Server Actions)
Language TypeScript
Database PostgreSQL 16
ORM Drizzle ORM
Auth Better Auth (email + password)
UI Tailwind CSS + shadcn/ui
Charts Recharts
LLM OpenAI GPT-4o-mini + Tavily Search + Perplexity Sonar
Deployment Docker Compose + Traefik reverse proxy

Quick Start

Prerequisites

  • Node.js 20+
  • PostgreSQL 16+ (or Docker)
  • At least one LLM API key

1. Clone & Install

git clone https://gitea.tophermayor.com/TopherMayor/comparaison.git
cd comparaison
npm install

2. Configure Environment

cp .env.example .env.local
# Edit .env.local with your API keys and database URL

Required environment variables:

Variable Description Required
DATABASE_URL PostgreSQL connection string Yes
BETTER_AUTH_SECRET Random secret for session signing Yes
OPENAI_API_KEY OpenAI API key (GPT-4o-mini) Yes*
TAVILY_API_KEY Tavily search API key Recommended
PERPLEXITY_API_KEY Perplexity Sonar API key Optional
NEXT_PUBLIC_APP_URL Public URL of the app Yes

*At minimum, one LLM provider key is required. OpenAI works standalone; Tavily adds web search; Perplexity adds cheaper synthesis.

3. Database Setup

# Generate migration
npx drizzle-kit generate

# Run migration
npx drizzle-kit migrate

4. Development

npm run dev
# App runs at http://localhost:3000

5. Docker Deployment

docker compose up -d

Deployment

Production URL: https://comparaison.local.tophermayor.com

Detail Value
Host ubuntu (192.168.50.61)
Compose file /srv/compose/comparaison/docker-compose.yml
Reverse proxy Traefik (shared instance on proxy-net)
Database Shared PostgreSQL (postgres-shared container on proxy-net)
Routing Docker labels on the app container (Traefik router/rules)

Production Setup

  1. Traefik Ingress — A shared Traefik instance handles TLS termination and routes traffic to the app container via Docker labels. The app joins the proxy-net network so Traefik can reach it.

  2. Shared PostgreSQL — A standalone postgres-shared container provides the database. The comparaison app connects to it over proxy-net. No separate DB container is defined in the app's compose file.

  3. Environment — The following are configured in the production environment:

    • DATABASE_URL — Points to the shared Postgres instance
    • BETTER_AUTH_SECRET — Random secret for session signing
    • OPENAI_API_KEY, TAVILY_API_KEY, PERPLEXITY_API_KEY — LLM provider keys
    • NEXT_PUBLIC_APP_URLhttps://comparaison.local.tophermayor.com

Deploying Updates

# On ubuntu (192.168.50.61)
cd /srv/compose/comparaison
docker compose pull && docker compose up -d

Recent Fixes

  • Added userId to comparison inserts so saved comparisons are properly associated with authenticated users
  • Fixed OpenAI provider getClient() to correctly initialize the OpenAI client
  • Added BETTER_AUTH_SECRET to production environment for proper session management

Project Structure

src/
├── app/
│   ├── (auth)/              # Auth route group
│   │   ├── sign-in/         # Sign in page
│   │   └── sign-up/         # Sign up page
│   ├── (main)/              # Main app route group (with nav)
│   │   ├── compare/         # Comparison input + results
│   │   ├── explore/         # Public comparisons feed
│   │   └── profile/         # User profile + saved comparisons
│   ├── api/
│   │   ├── auth/[...all]/   # Better Auth catch-all
│   │   └── compare/         # SSE streaming research endpoint
│   ├── layout.tsx           # Root layout
│   └── page.tsx             # Landing page
├── components/
│   ├── comparison/          # Visualization components
│   │   ├── radar-chart.tsx
│   │   ├── bar-chart.tsx
│   │   ├── comparison-table.tsx
│   │   ├── score-card.tsx
│   │   └── pros-cons-card.tsx
│   └── ui/                  # shadcn/ui components
├── hooks/
│   └── use-comparison-stream.ts  # SSE streaming hook
├── lib/
│   ├── auth.ts              # Better Auth server config
│   ├── auth-client.ts       # Better Auth client
│   ├── db/
│   │   ├── index.ts         # Drizzle client
│   │   └── schema.ts        # Database schema
│   ├── llm/
│   │   ├── index.ts         # Research pipeline orchestrator
│   │   ├── types.ts         # LLM type definitions
│   │   └── providers/
│   │       ├── index.ts     # Provider fallback chain
│   │       ├── openai.ts    # OpenAI GPT-4o-mini provider
│   │       ├── tavily.ts    # Tavily search provider
│   │       └── perplexity.ts # Perplexity Sonar provider
│   ├── types.ts             # Shared type definitions
│   └── utils.ts             # Utility functions
└── middleware.ts             # Auth middleware + route protection

Architecture

See docs/architecture.md for detailed architecture documentation.

API Reference

See docs/api-reference.md for endpoint documentation.

UI/UX Flow

See docs/ui-ux-flow.md for user journey and wireframe descriptions.

License

MIT

Description
AI-Powered Deep Research Comparison Platform
Readme 483 KiB
Languages
TypeScript 97%
CSS 2.4%
JavaScript 0.3%
Dockerfile 0.3%