Get alerts the moment competitors change pricing, launch new features, reposition messaging, update landing pages, or make strategic moves.
A B2B SaaS for competitive intelligence. Not another analytics dashboard — an actionable alerting platform.
| Layer | Tech |
|---|---|
| Frontend | Next.js 15 (App Router) · TypeScript · Tailwind · shadcn/ui |
| Backend | Next.js Route Handlers + Server Actions |
| Database | PostgreSQL + Prisma |
| Auth | Clerk |
| Worker | Node.js + BullMQ + Redis |
| Scraping | fetch + Cheerio (Playwright planned) |
| AI | OpenAI (gpt-4o-mini by default) |
| Resend |
The Next.js app and the worker share one Prisma schema and Redis instance, but run as two separate processes.
.
├── prisma/
│ └── schema.prisma # User, Competitor, MonitoredPage, Snapshot, Alert
├── src/
│ ├── app/
│ │ ├── (auth)/ # Clerk sign-in / sign-up
│ │ ├── api/ # REST endpoints (competitors, alerts, pages/[id]/check, health)
│ │ ├── dashboard/ # Authenticated app
│ │ ├── globals.css # Tailwind + theme tokens
│ │ ├── layout.tsx
│ │ └── page.tsx # Landing page
│ ├── components/
│ │ ├── ui/ # shadcn primitives
│ │ ├── marketing/ # Landing page sections
│ │ └── dashboard/ # Dashboard widgets
│ ├── lib/ # prisma, redis, openai, resend, utils, validators
│ ├── server/
│ │ ├── auth.ts # requireUser / getOrCreateCurrentUser
│ │ ├── actions.ts # Server actions (CRUD)
│ │ ├── queue.ts # BullMQ queue (shared with worker)
│ │ └── monitoring/
│ │ ├── scraper.ts # fetch + extract + normalize
│ │ ├── differ.ts # structured diff + prompt builder
│ │ ├── summarizer.ts # OpenAI prompt + fallback
│ │ ├── notifier.ts # Resend email
│ │ └── pipeline.ts # End-to-end check
│ └── middleware.ts # Clerk route guard
└── worker/
└── index.ts # BullMQ worker + DB-driven scheduler
# 1. Install deps
npm install
# 2. Copy env
cp .env.example .env
# Fill in DATABASE_URL, CLERK_*, OPENAI_API_KEY, REDIS_URL, RESEND_API_KEY
# 3. Push schema to your DB
npm run db:push
# 4. Start the web app
npm run dev
# 5. In a second terminal, start the worker
npm run worker:devRequires:
- Node 20+
- PostgreSQL 14+
- Redis 6+ (for BullMQ)
┌──────────────┐
│ Scheduler │ ← runs every minute inside worker/
│ (DB-driven) │ selects pages with nextCheckAt ≤ now
└──────┬───────┘
│ enqueues job
▼
┌──────────────┐
│ BullMQ Queue │
│ (Redis) │
└──────┬───────┘
│
▼
┌────────────────────────────────────────────────────────────────────┐
│ runMonitoringCheck(pageId) │
│ │
│ fetchUrl ── extractContent ── hash ── compare with last snapshot │
│ │ │
│ unchanged ──────────┘ │
│ │
│ changed ─► computeDiff ─► summarizeDiff │
│ │ │
│ ▼ │
│ create Alert + send email │
└────────────────────────────────────────────────────────────────────┘
Key design decisions:
- Hash comparison before diff keeps unchanged pages cheap.
- Diff before AI. We never send raw HTML to OpenAI. The model only sees a compact structured representation (added/removed lines, pricing changes, headings).
- Pricing & feature heuristics are extracted at scrape-time, so the diff can call out "Pro plan went from $99 → $79" even when the AI is unavailable.
- Fallback summarizer runs deterministically if
OPENAI_API_KEYis missing or the API call fails. The product still produces useful alerts.
- Sign up at
/sign-up. - Go to Dashboard → Add competitor.
- Open the competitor and click Add page to monitor a URL (homepage, pricing, changelog…).
- The first check runs immediately. Subsequent checks run on the schedule you chose.
- Slack notifications & weekly digests
- Playwright-rendered scraping for JS-heavy apps
- Pricing history timelines
- Public API (Team plan)
- Browser extension