Skip to content

shreyaabaranwal/CompCompass

Repository files navigation

🧭 CompCompass — Compensation Intelligence

Because a job title tells you nothing — a level tells you everything.

Salary data modeled around the tuple company → level → role → location, with levels made comparable across companies via a universal seniority rank (1–10). So you get a real answer to "Is Google L4 the same as Amazon SDE-2?" (yes — both rank 4).

Two pieces of real engineering

  • Level Equivalence Engine (src/lib/levels.ts) — every company label (L4, SDE-2, E4, IC3, MSFT 62) maps to a universal rank. Comparison groups by rank, not title.
  • Data Trust Score (src/lib/comp.ts) — every company×level aggregate carries a 0–100 score from sample size, freshness, and IQR spread, surfaced as 🟢🟡🔴. Groups with < 3 entries are hidden.

Stack

Next.js (App Router) · TypeScript · Prisma · PostgreSQL (Neon) · Zod · Recharts

Quick start

npm install
cp .env.example .env          # paste your Neon connection string into DATABASE_URL
npm run db:generate           # prisma generate
npm run db:migrate -- --name init
npm run db:seed               # ~400 realistic entries
npm run dev                   # http://localhost:3000

# in a second terminal, hammer the API edge cases:
npm run test:api

Core logic (src/lib)

File Responsibility
normalize.ts company-name + level + role normalization → slugs
levels.ts universal level→rank mapping (the differentiator)
comp.ts total-comp formula, percentiles, aggregation, trust score, dedup fingerprint
validation.ts Zod schemas at every API boundary
ingest.ts shared write path: validate → normalize → rank → compute → dedup → store

Total comp is computed at write-time and stored for fast reads: TC = base + stockGrant/vesting + (targetBonus + signOn/vesting). Missing stock/bonus default to 0. Dedup is a SHA-256 fingerprint over the entry's identifying fields (unique DB column → duplicate single submit returns 409; duplicate CSV rows are skipped and reported, batch still succeeds).

API

Method Route Purpose Status
POST /api/salaries ingest one entry 201 400 409
GET /api/salaries list + filter + sort + paginate 200
POST /api/salaries/import CSV bulk import 200 400
GET /api/companies/[slug] aggregated comp by level + trust 200 404
GET /api/compare?companies=a,b apples-to-apples by rank 200 400
POST/GET /api/comparisons save / list (auth) 200 201 401

Auth for saved comparisons is intentionally thin (an x-user-email header / cookie identifies the user) so the flow is demonstrable without a full auth provider; swap in a real session in production.

Tests

  • npm run test:api — curl edge cases: valid, missing-stock, duplicate (409), negative/garbage input (400), name normalization, unknown company (404), compare arity, auth gating.
  • Core logic has been unit-verified (normalization, TC, percentiles, trust, dedup, level equivalence).

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors